IOS9 & Security: App Transport Security Breaks Everything

ATS lets apps add declarations to Info.plist specifying which domains require secure communication. Guess who Apple invited to the security party? EVERYONE ON THE INTERNET

As of iOS9 and OS X 10.10 (El Capitan), API classes NSURLConnection and NSURLSession(& CFURL opaque types) now make network requests using HTTPS by default. HTTP requests (transmitting data as cleartext) will now result in an exception being thrown a la

CFNetwork SSLHandshake failed (-9801)
Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made."

ATS impels developers and content providers to establish secure networking best practices, namely TLS1.2 (successor to SSL, secure hashing protocols w/symmetric cryptography) with specific forward secrecy (PFS) ciphers (preventing compromise of previously encrypted data in the event that an attacker gains access to a secret key). Other requirements include SHA256 fingerprint with at least a 2048 bit RSA keys / 256 bit Elliptic-Curve (ECC) keys for all certificates (to render known brute-force attacks ineffectual, excepting poor implementation of Diffie-Hellman protocol [i.e. hard-coding of primes] and/or getting lucky brute-forcing a particular prime) in addition to omission of known insecure crypto primitives (SHA-1 ||RC4).

But what if my content delivery network (CDN) doesn’t support HTTPS?

I. ATS enabled w/exceptions

If most but not all of our domain requests will comply with ATS, exceptions can be made by creating a dictionary for the domain (or sub-domain) we want to opt-out in NSExceptionDomains →set NSExceptionAllowsInsecureHTTPLoads = YES (or NSExceptionRequiresForwardSecrecy/ and NSExceptionMinimumTLSVersion et al. for specific rules about supporting PFS or TLS versions, respectively).

II. ATS disabled w/exceptions

If we know we want to support ATS for things like login calls but also want to be able to load countless other URLs (e.g. twitter APIs), disable ATS with NSAllowsArbitraryLoads = YES then define secure domains in NSExceptionDomains dictionary →set NSExceptionAllowsInsecureHTTPLoads = NO

III. The last resort (a.k.a. the Google-Ads workaround)

What happens when we need to load arbitrary content, or we don’t know all the insecure domains our app needs to access, or we just don’t care about security?

“While Google remains committed to industry-wide adoption of HTTPS, there isn’t always full compliance on third party ad networks and custom creative code served via our systems. To ensure ads continue to serve on iOS9 devices for developers transitioning to HTTPS, the recommended short term fix is to add an exception that allows HTTP requests to succeed and non-secure content to load successfully.” - Google Ads Dev Blog

set NSAllowsArbitraryLoads = YES in Info.plist.

Debugging ATS Issues

Checking requests in OSX EC/10.11 with NSCurl

In Terminal: $ nscurl --ats-diagnostics [-verbose] https://someurl…

Runs through several different combinations of ATS exceptions, including “allow arbitrary loads” flag, dropping minimum required TLS versions in sequence (TLS1.2 →1.1 →1.0), and removing the Perfect Forward Secrecy (PFS) requirement.


In Xcode toolbar, select target(your project)→ select “edit scheme” → add CFNETWORK_DIAGNOSTICS to Environment Variables and set between 1-3 (least to most verbose). This will create a log of all NSURLSession errors including the URL that was called and the ATS error that resulted.

Don’t be confused by NSThirdParty keys

NSThirdPartyException… keys are functionally identical to their non-third party key brethren.

Further Reading