OnionBrowser / OnionBrowser

An open-source, privacy-enhancing web browser for iOS, utilizing the Tor anonymity network
https://onionbrowser.com
Other
2.3k stars 448 forks source link

iOS seems to be leaking OCSP outside of Onion Browser #178

Closed r3ckd closed 5 years ago

r3ckd commented 5 years ago

UPDATE, JUNE 15 2019: See advisory note & summary about this leak:
2019-178: sites with EV HTTPS certificates leak information via OCSP

Original GitHub issue:


Onion Browser on iOS is leaking data about some visited sites (both onion services and clearnet hosted servers). This happens because the browser checks for certificate revocations with OCSPv1 over non tor transport.

OCSP requests and responses made by Onion Browser goes via regular network, and since these are HTTP requests, any party with enough access to network can sniff it and identify the domains user is visiting.

Steps to reproduce

Consider a scenario where user is connected to an evil access point running tcpdump, and tries visiting “www.nytimes3xbfgragh.onion” in Onion Browser.

As you can see, the OCSP request is going via non TOR transport in HTTP and we can dump and Identify the domain.

We were also able to reproduce it for other OCSPv1 services - we tested

  1. https://www.grindr.com
  2. https://check.torproject.org
  3. https://nytimes.com
  4. https://flixbus.com/

We can also provide the packet dumps if you need.

Decoding an OCSP response
=========================
n8fr8 commented 5 years ago

Interesting comments here: https://stackoverflow.com/questions/5625642/crl-and-ocsp-behavior-of-ios-security-framework

"To sum it up, there are several things to keep in mind for OCSP implementation on iOS:

OCSP policy cannot be configured at this moment
it works for the EV certificates only
high-level stuff, such as NSURLConnection or UIWebView use TLS security policy, which uses OCSP
SecTrustEvaluate is a blocking network operation
it works the "best attempt" - if OCSP server cannot be contacted, the trust evaluation will not fail

"

n8fr8 commented 5 years ago

and here: https://web.archive.org/web/20121026094830/http://www.inmite.eu/en/blog/20120302-details-certificate-revocation-mechanisms-on-ios-iphone

Seems like this only happens with "EV" certificates

mtigas commented 5 years ago

interestingly enough, there's a block here that i believe is used for determining trust/validity and EV status https://github.com/OnionBrowser/OnionBrowser/blob/f211932ad6ec534096e1c71efe4f339ab784a908/Endless/SSLCertificate.m#L34-L54

but all of those functions (SecTrustGetCertificateAtIndex, SecTrustCopyResult, etc) seem to be after iOS has evaluated trust? (i don't see anything in here where our code/endless code explicitly sends something up for trust evaluation.)

but this might be a good place to start experimenting with changes.

mtigas commented 5 years ago

I have documented everything I know about this bug (basically summarized my research that I spewed out in chat a couple weeks ago) on the GitHub wiki for the app:

https://github.com/OnionBrowser/OnionBrowser/wiki/2019-178:-sites-with-EV-HTTPS-certificates-leak-information-via-OCSP

I'll be linking to it from the homepage, default app homepage, and other places I think.

mirokuratczyk commented 5 years ago

Upon seeing this issue we realized that our project (https://github.com/Psiphon-Inc/endless), which relies on proxying UIWebView with an NSURLProtocol subclass, has the same issue with OCSP requests leaking in plaintext.

Our Solution

This is just a quick overview, but we can provide more details or provide instructions on how to integrate OCSPCache.

OCSPCache

https://github.com/Psiphon-Labs/OCSPCache

We created a CocoaPod for making OCSP requests and caching OCSP responses on iOS. This includes handling authentication challenges with a default series of revocation checks.

Revocation checking

Our solution roughly takes the following steps.

1. Check if there is a pinned OCSP response
// Use this policy for checking all OCSP responses to ensure
// that no plaintext OCSP requests are made by the system.
SecPolicyRef = SecPolicyCreateRevocation(kSecRevocationOCSPMethod |
                                         kSecRevocationRequirePositiveResponse |
                                         kSecRevocationNetworkAccessDisabled);
SecTrustSetPolicies(trust, policy);

If SecTrustEvaluate succeeds, then there was a pinned OCSP response.

2. Make proxied OCSP requests

If there is no pinned OCSP response, or the pinned response was invalid, make proxied OCSP requests manually. This is done by either modifying all OCSP request URLs to point through our local reverse proxy or by providing an NSURLSession with the connection proxy dictionary set to use our local HTTP or SOCKS proxy.

3. Fallback to CRL

If the previous OCSP checks fail, fallback to system revocation checking with CRLs.


Some comments on getting OCSP URLs from a SecTrust object and constructing OCSP requests can be found in: https://github.com/Psiphon-Labs/OCSPCache/blob/b945a5784cd88ed5693a62a931617bd371f3c9a8/OCSPCache/Classes/OCSPCert.h.

tladesignz commented 5 years ago

@mirokuratczyk This is great, thanks a lot!

Can you point me to the place where you use this, so I can get an idea? Or is that part of Psiphon closed source?

Unfortunately, we can't add the package just like that, as we're using Swift, also, which makes OpenSSL-Universal unusable due to the statically linked libraries. (See an explanation about this here: https://github.com/googlemaps/google-maps-ios-utils/blob/master/Swift.md) So we first need to figure out a way to include this in the most elegant way possible.

mirokuratczyk commented 5 years ago

@tladesignz No problem!

We use this in our NSURLProtocol subclass here.

Also, we have sample apps which we updated to use OCSPCache as well: TunneledWebRequest and TunneledWebView. TunneledWebView has a more straight forward integration.


I think CocoaPods added support for statically linked libraries in 1.5.0: http://blog.cocoapods.org/CocoaPods-1.5.0/.

pod install with the following change seems to work (using CocoaPods 1.7.3):

-use_frameworks!
+use_modular_headers!

Although, I did not look into the implications of use_modular_headers!.

tladesignz commented 5 years ago

@mirokuratczyk Awesome! Thanks a ton!

mirokuratczyk commented 5 years ago

We have found a few bugs in the OCSPCache code while reviewing it with Apple through a support ticket.

Quick summary below:

These bugs are confined to AuthURLSessionDelegate, which provides some default certificate validation code. We are working on fixes for these, but the AuthURLSessionDelegate should not be used in its current state.

I'll provide an update when the fixes are released!

tladesignz commented 5 years ago

@mirokuratczyk I dived deep into all the interceptor code. I replaced ours with yours (basically your JAHPAuthenticatingHTTPProtocol stuff) so I get the OCSPCache support and also because that seems way better than our CFNetwork usage. (Thanks a ton for that!)

AuthURLSessionDelegate should not be used in its current state.

Well, why not? The issues you describe still seem to be better than leaking IPs via OCSP calls. How big is the chance that an exit node gets ahold of an intermedia certificate which was revoked or of a sibling server's cert and tries MitM traffic with these compared to the problem of actually always leaking IP addresses with OCSP requests to a state censor?

Or do I have a thought error there?

I'm almost finished adapting your code to OnionBrowser, however I ran into some issues. Check out this site: https://badssl.com

Most of the links are completely breaking. Meaning no timeout just endless loading. That's not good.

I'll provide an update when the fixes are released!

Not trying to get annoying, but can you provide a horizon of when to expect these?

BTW.: I got really annoyed with the CSP header mangling from Endless, so I did it "right". Check this out:

https://cocoapods.org/pods/CSPHeader https://github.com/OnionBrowser/OnionBrowser/blob/cce6300cfb20bfde33fa7a1627b04e3c7ae4a1bc/Psiphon/JAHPAuthenticatingHTTPProtocol.m#L1275-L1320

I guess, that's usable for you, too!

mirokuratczyk commented 5 years ago

@tladesignz that's great to hear!

Well, why not? The issues you describe still seem to be better than leaking IPs via OCSP calls. How big is the chance that an exit node gets ahold of an intermedia certificate which was revoked or of a sibling server's cert and tries MitM traffic with these compared to the problem of actually always leaking IP addresses with OCSP requests to a state censor?

That's a valid point. I agree that the risk of leaking OCSP requests is worse.

I'm almost finished adapting your code to OnionBrowser, however I ran into some issues. Check out this site: https://badssl.com Most of the links are completely breaking. Meaning no timeout just endless loading. That's not good.

I checked it out and you are right. I think the issue is that, currently, the default timeout for network requests on iOS is used for OCSP requests. An NSURLSession with ephemeralSessionConfiguration is used unless an NSURLSession is explicitly provided to OCSPAuthURLSessionDelegate. This default timeout is quite long and I believe some of the OCSP servers corresponding to some certs on https://badssl.com are not responding to the requests; hence the endless loading caused by certificate validation being stuck on the OCSP step.

Allowing timeout configuration seems to fix this (included in the PR mentioned below). I set the timeout for OCSP requests to 1s and the tests load quickly. If you get a chance, it would be great to know if the same works for you.

Not trying to get annoying, but can you provide a horizon of when to expect these?

The fixes for the issues mentioned in my previous comment and above are completed, but not yet merged: https://github.com/Psiphon-Labs/OCSPCache/pull/6. I'll be AFK for the next week, but i'll do some further tests, merge and make an official release next week -- assuming everything goes smoothly.

You can work off of my fork if you'd like to test the changes before they are merged.

https://cocoapods.org/pods/CSPHeader

This looks great, thanks! We can definitely use this.

tladesignz commented 5 years ago

Allowing timeout configuration seems to fix this (included in the PR mentioned below). I set the timeout for OCSP requests to 1s and the tests load quickly. If you get a chance, it would be great to know if the same works for you.

Yay! That works, thanks!

Please give me a heads up, when you do a release, so I don't need to point to your fork anymore!

mirokuratczyk commented 5 years ago

Yay! That works, thanks!

Good to hear!

I've merged the changes in my fork so you can switch over.

OlexandrStepanov commented 4 years ago

Hello @mirokuratczyk,

I have found this issue from rdar://716337334. I'm investigating OCSP revocation check from Alamofire's ServerTrustEvaluation, RevocationTrustEvaluator class.

I'm wondering, you mention here and in radar "pinned OCSP response" term. Did you mean, that when one specifies (kSecRevocationOCSPMethod | kSecRevocationNetworkAccessDisabled) flag it will effectively check for OCSP Stapling? Or you meant some other OCSP pin?

Any feedback would be greatly appreciated.

mirokuratczyk commented 4 years ago

Hi @OlexandrStepanov,

Did you mean, that when one specifies (kSecRevocationOCSPMethod | kSecRevocationNetworkAccessDisabled) flag it will effectively check for OCSP Stapling? Or you meant some other OCSP pin?

Yes, I meant that it will effectively check for OCSP stapling. This was confirmed by Apple and through our testing. Thanks for pointing this ambiguity out! I updated my comment on the rdar to specifically mention OCSP stapling.