App Transport Security (ATS) enforces best practices in the secure connections between an app and its back end. ATS prevents accidental disclosure, provides secure default behavior, and is easy to adopt; it is also on by default in iOS 9 and OS X v10.11. You should adopt ATS as soon as possible, regardless of whether you’re creating a new app or updating an existing one.
If you’re developing a new app, you should use HTTPS exclusively. If you have an existing app, you should use HTTPS as much as you can right now, and create a plan for migrating the rest of your app as soon as possible. In addition, your communication through higher-level APIs needs to be encrypted using TLS version 1.2 with forward secrecy. If you try to make a connection that doesn’t follow this requirement, an error is thrown. If your app needs to make a request to an insecure domain, you have to specify this domain in your app’s Info.plist file.

This is in a nutshell what App Transport Security (ATS) is all about. It basically encourages security by imposing a number of security best practices.

Let’s say you create a brand new iOS project and you do a network request like this:

Alamofire.request(.GET, "http://httpbin.org")

If you run your app the console output shows the following message immediately after making the request

App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.

This is App Transport Security doing what does best: protecting us against insecure network calls. This is a feature that enforces HTTPS-only calls. But wait a minute … What if i have already an insecure HTTP API ? Maybe i need time to upgrade or maybe i really don’t care (you should). What if I’m consuming a 3rd party API that no ones know when the maintainer will make the transition or isn’t planned ? Luckily there are solutions and workarounds to those issues.

Like the last message says you can configure exceptions to the Info.plist file. Lets do that:

Arbitrary Loads Meme

This will ignore all app transport security restrictions. Another way to add this kind of rules is just right-click in the Info.plist file and select Open As -> Source Code, The following code will do the trick.

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

Now if you run your app again the request will be made and you will continue to work with all that fancy network stuffs that you already do.

All The Things Meme

Not so fast. This doesn’t feel quite right, bypass all the restrictions feels like a temporary solution for testing and development purposes and maybe for some kind of apps. In fact if you deploy this to the store without a good reason, you may risk rejection as mentioned in this commented thread:

I want to make sure everyone fully understands this behavior. I spent some time in the labs last week at WWDC, and got the following information.
Setting NSAllowsArbitraryLoads to true will allow it to work, but Apple was very clear in that they intend to reject apps who use this flag without a specific reason. The main reason to use NSAllowsArbitraryLoads I can think of would be user created content (link sharing, custom web browser, etc). And in this case, Apple still expects you to include exceptions that enforce the ATS for the URLs you are in control of.
If you do need access to specific URLs that are not served over TLS 1.2, you need to write specific exceptions for those domains, not use NSAllowsArbitraryLoads set to yes. You can find more info in the NSURLSesssion WWDC session.
Please be careful in sharing the NSAllowsArbitraryLoads solution. It is not the recommended fix from Apple.

The most common approach is to add per-domain exceptions. All the keys for each excepted domain are optionals.

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>httpbin.org</key>
        <dict>
            <key>NSIncludesSubdomains</key>
            <false/>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <false/>
            <key>NSExceptionRequiresForwardSecrecy</key>
            <true/>
            <key>NSExceptionMinimumTLSVersion</key>
            <string>TLSv1.2</string>
            <key>NSRequiresCertificateTransparency</key>
            <false/>
        </dict>
    </dict>
</dict>

There are other keys, like: NSThirdPartyExceptionAllowsInsecureHTTPLoads, NSThirdPartyExceptionRequiresForwardSecrecy, NSThirdPartyExceptionMinimumTLSVersion that seems to be duplicates with the addition of “ThirdParty” in the name. Some resources explain that they behave the same way as their counterparts, the actual code behind them is identical whether you use the ThirdParty keys or not.

The key names are very descriptive:

  • NSIncludesSubdomains: Useful for when we have scenarios in which the main domain (mydomain.com) is over https but some subdomains (cdn.mydomain.com) aren’t. So it tells App Transport Security that the exception applies to every subdomain of the specified domain
  • NSExceptionAllowsInsecureHTTPLoads: If included this key allows us to use insecure http. The only trick here seems that when specified, every requirement of App Transport Security for that domain is overridden.
  • NSExceptionRequiresForwardSecrecy && NSExceptionMinimumTLSVersion: App Transport Security requires TLS 1.2 and it expects the domain to support forward secrecy. This are currently the best practices for secure network connections enforced by ATS. This page provides more info regarding this configuration options.
  • NSRequiresCertificateTransparency: Currently this is disabled by default but if your server support certificate transparency you should opt-in this key.

Now at last lets talk about some tricks that i use. Personally every time i need to include this kind of rules a google search mandatory, is almost impossible to remember from time to time the proper structure and keys to use.

A really good way to tackle this problem is to use snippets. I found two handy ways to do so, one is using our old friend Xcode and his built-in snippets functionality and the other one is to use the awesome Dash app that has already a super handy built-in snippet feature. In both of them you can include placeholders to fill some sections like the domain name.

This is how it looks like when using Dash snippets and then I remove the sections that aren’t necessary for this particular case.

Autocomplete Snippet

Final Snippet

If you run your app again the network request will work flawlessly without any warning. This is basically all that you need to know to get started. If you have any opinion or suggestion contact me on Twitter.

Further reading: