ios - How to use NSURLConnection to connect with SSL for an untrusted cert?

ID : 10229

viewed : 51

Tags : iosobjective-chttpsssl-certificateapp-transport-securityios

Top 5 Answer for ios - How to use NSURLConnection to connect with SSL for an untrusted cert?

vote vote

94

There is a supported API for accomplishing this! Add something like this to your NSURLConnection delegate:

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace {   return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]; }  - (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {   if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])     if ([trustedHosts containsObject:challenge.protectionSpace.host])       [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];    [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge]; } 

Note that connection:didReceiveAuthenticationChallenge: can send its message to challenge.sender (much) later, after presenting a dialog box to the user if necessary, etc.

vote vote

85

If you're unwilling (or unable) to use private APIs, there's an open source (BSD license) library called ASIHTTPRequest that provides a wrapper around the lower-level CFNetwork APIs. They recently introduced the ability to allow HTTPS connections using self-signed or untrusted certificates with the -setValidatesSecureCertificate: API. If you don't want to pull in the whole library, you could use the source as a reference for implementing the same functionality yourself.

vote vote

71

Ideally, there should only be two scenarios of when an iOS application would need to accept an un-trusted certificate.

Scenario A: You are connected to a test environment which is using a self-signed certificate.

Scenario B: You are Proxying HTTPS traffic using a MITM Proxy like Burp Suite, Fiddler, OWASP ZAP, etc. The Proxies will return a certificate signed by a self-signed CA so that the proxy is able to capture HTTPS traffic.

Production hosts should never use un-trusted certificates for obvious reasons.

If you need to have the iOS simulator accept an un-trusted certificate for testing purposes it is highly recommended that you do not change application logic in order disable the built in certificate validation provided by the NSURLConnection APIs. If the application is released to the public without removing this logic, it will be susceptible to man-in-the-middle attacks.

The recommended way to accept un-trusted certificates for testing purposes is to import the Certificate Authority(CA) certificate which signed the certificate onto your iOS Simulator or iOS device. I wrote up a quick blog post which demonstrates how to do this which an iOS Simulator at:

accepting untrusted certificates using the ios simulator

vote vote

67

NSURLRequest has a private method called setAllowsAnyHTTPSCertificate:forHost:, which will do exactly what you'd like. You could define the allowsAnyHTTPSCertificateForHost: method on NSURLRequest via a category, and set it to return YES for the host that you'd like to override.

vote vote

60

To complement the accepted answer, for much better security, you could add your server certificate or your own root CA certificate to keychain( https://stackoverflow.com/a/9941559/1432048), however doing this alone won't make NSURLConnection authenticate your self-signed server automatically. You still need to add the below code to your NSURLConnection delegate, it's copied from Apple sample code AdvancedURLConnections, and you need to add two files(Credentials.h, Credentials.m) from apple sample code to your projects.

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace { return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]; }  - (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { //        if ([trustedHosts containsObject:challenge.protectionSpace.host])      OSStatus                err;     NSURLProtectionSpace *  protectionSpace;     SecTrustRef             trust;     SecTrustResultType      trustResult;     BOOL                    trusted;      protectionSpace = [challenge protectionSpace];     assert(protectionSpace != nil);      trust = [protectionSpace serverTrust];     assert(trust != NULL);     err = SecTrustEvaluate(trust, &trustResult);     trusted = (err == noErr) && ((trustResult == kSecTrustResultProceed) || (trustResult == kSecTrustResultUnspecified));      // If that fails, apply our certificates as anchors and see if that helps.     //     // It's perfectly acceptable to apply all of our certificates to the SecTrust     // object, and let the SecTrust object sort out the mess.  Of course, this assumes     // that the user trusts all certificates equally in all situations, which is implicit     // in our user interface; you could provide a more sophisticated user interface     // to allow the user to trust certain certificates for certain sites and so on).      if ( ! trusted ) {         err = SecTrustSetAnchorCertificates(trust, (CFArrayRef) [Credentials sharedCredentials].certificates);         if (err == noErr) {             err = SecTrustEvaluate(trust, &trustResult);         }         trusted = (err == noErr) && ((trustResult == kSecTrustResultProceed) || (trustResult == kSecTrustResultUnspecified));     }     if(trusted)         [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge]; }  [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge]; } 

Top 3 video Explaining ios - How to use NSURLConnection to connect with SSL for an untrusted cert?

Related QUESTION?