Working with Apple’s App Transport Security

Update 6/23/15: Apple now has official documentation for App Transport Security.

With iOS 9 and OS X El Capitan, Apple has introduced App Transport Security. In a nutshell, App Transport Security enforces best practices for secure network connections — notably, TLS 1.2 and forward secrecy. In the future, Apple will also update these best practices to ensure they always reflect the latest security practices that will keep network data secure.

App Transport Security is enabled by default when using NSURLSession, NSURLConnection, or CFURL in iOS 9 or OS X El Capitan. Unfortunately for many developers this may mean that things break as soon as they build for iOS 9 or OS X 10.10. Fortunately Apple offers some configuration options to leverage App Transport Security where possible, while disabling it in places where you cannot support it.

You can opt-out of ATS for certain URLs in your Info.plist by using NSExceptionDomains. Within the NSExceptionDomains dictionary you can explicitly define URLs that you need exceptions for with ATS. The exceptions you can use are: NSIncludesSubdomains
NSExceptionAllowsInsecureHTTPLoads
NSExceptionRequiresForwardSecrecy
NSExceptionMinimumTLSVersion
NSThirdPartyExceptionAllowsInsecureHTTPLoads
NSThirdPartyExceptionMinimumTLSVersion
NSThirdPartyExceptionRequiresForwardSecrecy
Each of these keys allows you to granularly disable ATS or particular ATS options on domains where you are unable to support them.

Sample ATS plist

In the first beta of iOS 9, these keys are incorrect and instead you’ll need to use the following: NSTemporaryExceptionAllowsInsecureHTTPLoads
NSTemporaryExceptionRequiresForwardSecrecy
NSTemporaryExceptionMinimumTLSVersion
NSTemporaryThirdPartyExceptionAllowsInsecureHTTPLoads
NSTemporaryThirdPartyExceptionMinimumTLSVersion
NSTemporaryThirdPartyExceptionRequiresForwardSecrecy

These keys will undoubtedly be fixed in a future seed. If you can, you should use the first set of keys above that Apple is officially supporting, though if you’re using the temporary keys, they should continue to work in future betas. Thanks to Juan Leon for bringing this to my attention—I was told the same in the labs.

Below are examples of different scenarios developers may encounter.

Example A: ATS for all

This is the easiest one. The only thing you need to do is use NSURLSession, NSURLConnection, or CFURL. If you’re targeting iOS 9 or OS X El Capitan or later, ATS’s best practices will apply to all of your NSURLSession, NSURLConnection, and CFURL traffic.

Example B: ATS for all, with some exceptions

If you expect all of your domains to work with ATS, except a few that you know will not work, you can specify exceptions for where ATS should not be use, while leaving all other traffic opted in. For this scenario, you’ll want to use an NSExceptionDomains to specify the domains for which you wish to override ATS’s default settings. To opt-out an entire domain or sub-domain, create a dictionary for the URL you want to opt-out of ATS, then set NSExceptionAllowsInsecureHTTPLoadsto true. You can also specify more specific rules you wish to override with NSExceptionRequiresForwardSecrecy and NSExceptionMinimumTLSVersion if you don’t want to completely disable ATS on those domains.

ATS for All

Example C: ATS disabled, with some exceptions

Conversely, you may only want ATS to work on domains you specifically know can support it. For example, if you developer a Twitter client, there will be countless URLs you may want to load that may not be able to support ATS, though you would want things like login calls, and other requests to Twitter to use ATS. In this case you can disable ATS as your default, then specify URL which you do wish to use ATS.

In this case you should set NSAllowsArbitraryLoads to true, then define the URLs that you want to be secure in your NSExceptionDomains dictionary. Each domain you wish to be secure should have its own dictionary, and the NSExceptionAllowsInsecureHTTPLoads for that dictionary should be set to false.

ATS Disabled with Exceptions

Example D: Downgraded ATS

In some cases you may want ATS on all, or some, or your URLs, but are not ready to fully support all of ATS’s best practices. Perhaps your servers support TLS1.2, but don’t yet support forward secrecy. Rather than completely disabling ATS on the affected domains, you can leave ATS enabled, but disable forward secrecy. In this scenario you would create an NSExceptionDomains dictionary, a dictionary entry for each domain you need to override settings for, then set the NSExceptionRequiresForwardSecrecy value to false. Similarly, if you wish to have forward secrecy enabled, but need the minimum TLS version to be lower, you can define your supported TLS version with the NSExceptionMinimumTLSVersion key.

Downgraded ATS

Example E: NSA-friendly Mode

If you want to opt-out of ATS entirely (which you really shouldn’t do unless you fully understand the implications), you can simply set NSAllowsArbitraryLoads to true in your Info.plist.

NSA-friendly Mode

Third-party keys

You may have noticed a few keys that appear to be duplicates of others keys with the addition of “ThirdParty” in the name. NSThirdPartyExceptionAllowsInsecureHTTPLoads
NSThirdPartyExceptionMinimumTLSVersion
NSThirdPartyExceptionRequiresForwardSecrecy
Functionally these keys will have the same result as the keys that don’t have “ThirdParty” in them. The actual code being invoked behind the scenes will be identical regardless of whether you use the ThirdParty keys or not. You should probably use whichever key best fits your exceptions, but no need to overthink it.

Certificate Transparency

While most security features for ATS are enabled by default, certificate transparency is one you must opt-in to. If you have certificates which support certificate transparency, you can enable certificate transparency checks with the NSRequiresCertificateTransparency key. Again, if your certificates don’t yet support certificate transparency, by default this check will be disabled.

If you need help debugging issues that arise from having App Transport Security enabled, setting CFNETWORK_DIAGNOSTICS to 1 will log all NSURLSession errors including the URL that was called and the ATS error that resulted. Be sure to file radars for any issues you encounter so that ATS can be improved and flexibility expanded.

All of the above information was provided in Apple’s Networking with NSURLSession session at WWDC 2015. Finally, Apple emphasized in the talk to report any issues that you run into and keep any eye out for any changes that may be coming in future betas.

16 comments

  1. Dennis Christopher

    Great info. A question: does everything you have said about NSURLSession apply also if you are using NSURLConnection?

  2. Motti Shneor

    Few Questions: 1. What if I only know the domains I need exceptions for at runtime? In our case we have a secure connection to one server, which at times sends us the addresses of other servers we need to connect (Conferencing tool. first server is for control, the runtime-provided other servers are for media streaming). Can exceptions be provided at runtime via some API ?

    1. What about non-NSURLSession connections? What about CFSocket TCP connections? What about old ASIHTTPRequest based connections? does the system enforce ATS on these?

    2. You say “when you build for iOS-9”. If our application is already in the appstore, and was built using older SDK (8.4). Will ATS be enforced for it when running on iOS-9?

    I can’t seem to find the answers for these questions anywhere within Apple release notes, and WWDC sessions. Please help with any information, or even educated guess you have

    Thanks!

  3. Nick Arnott

    Dennis: To the best of my knowledge, none of the above applies if you are using NSURLConnection. It only applies to NSURLSession.

    Motti:

    1. I’m not aware of any way to specify exceptions at runtime.
    2. Non-NSURLSession connections should not be affected by any of this.
    3. If your app was built using 8.4 or earlier, ATS will not be enforced on iOS 9, or at least this seems to be the case with betas so far. My understanding is ATS will not apply until you submit an app that’s built with the 9.0+ SDK.

  4. Vignesh

    Thanks for the post. Really informative and clears things up! Quick question: How about existing apps that are targeting lower versions of the SDK (say 8.x). Is ATS turned-on for them when they run on iOS 9 ?

  5. James Watmuff

    Thanks for this. One correction:

    NSExceptionAllowInsecureHTTPLoads should be NSExceptionAllowsInsecureHTTPLoads (at least according to the official documentation)

  6. David DelMonte

    AFNetworking is third party, and available on Github. NSURLConnection is deprecated in iOS9, and we are now supposed to use NSURLSessionDataTask [[NSURLSession sharedSession] dataTaskWithURL:completionHandler: NSURLResponse, NSError

    It’s not required if you target iOS8.x instead of 9.

    However, in networking, it’s better to be up to date.

    You can find sample code out there ..

  7. Matthew To

    My server supports TLSv1.0, v1.1 and 1.2. But would my app block the connection by ATS in iOS9? Is it a must that my server have to support only TLSv1.2? Because my app currently won’t work unless I set NSAllowsArbitraryLoads to true. Thanks.

  8. Nick Arnott

    My comments above that stated this only applied to NSURLSession were incorrect. It also applies to NSURLConnection and CFURL. My apologies for the confusion. The article has been updated accordingly.

  9. Mark M

    One thing that tripped me up was that our SSL cert was only signed with SHA-1 which did not meet Apple’s requirements. The error code coming back was just (kCFStreamErrorDomainSSL, -9802) which is just a generic failure and didn’t help narrow things down.

  10. Klaus Busse

    In OS X El Capitan there is a great way to check the server in question and even get the necessary parameters to configure your app: In Terminal: nscurl –ats-diagnostics –verbose https://…

  11. Chris M.

    Nice post, one more correction in the images of your plist – it should be NSExceptionAllowsInsecureHTTPLoads not NSExceptionsAllowsInsecureHTTPLoads

  12. blabla

    Can NSExceptionRequiresForwardSecrecy be used outside of an NSExceptionDomain?

    I have found an app that looks like this:

    'NSAppTransportSecurity': { 'NSExceptionDomains': { 'NSExceptionRequiresForwardSecrecy': False, 'NSIncludeSubdomains': True, 'realdomain.com': {...} } },

    This looks like a misconfiguration to me, but if it isn’t, then what does it imply?

Post a comment

You may use the following HTML:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>