How to use NSURLConnection to connect with SSL for an untrusted cert?
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.
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
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.
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.