Yesterday, I wrote about App Transport Security and I showed you how to configure a project for App Transport Security. Despite Apple's bold move to enable App Transport Security by default for any build created with Xcode 7 and higher, many developers are confused, disabling it altogether.

That is not a good idea, though. Apple recently announced that every build submitted to the App Store needs to have App Transport Security enabled starting on 1 January 2017. It is important that you plan ahead and understand how this requirement impacts your applications.

In this tutorial, I would like to zoom in on exception domains. Exception domains allow you to specify which domains are exempt from the rules you define for App Transport Security.

Configuring App Transport Security

Before I discuss App Transport Security exception domains, I want to emphasize that the first decision you need to make is whether or not you opt in to App Transport Security. As I mentioned yesterday, there are four possible App Transport Security configurations.

  • Opt In
  • Opt Out
  • Opt In With Domain Exceptions
  • Opt Out With Domain Exceptions

If you opt in to App Transport Security, there is nothing you need to do. App Transport Security is enabled by default for any build created with Xcode 7 and higher. Even though App Transport Security is enabled by default, it can be helpful, for example if you are working in a team, to explicitly define the App Transport Security configuration by adding the following snippet to the target's Info.plist.

<key>NSAppTransportSecurity</key>
<dict>
  <key>NSAllowsArbitraryLoads</key>
  <false/>
</dict>

This block of XML explicitly defines that the application does not allow network request that don't comply with the strict rules defined by App Transport Security.

Opting out of App Transport Security is pretty easy as you can see below. The only difference with the previous example is that you explicitly opt out of App Transport Security by adding the following snippet to the target's Info.plist.

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

It is not recommended to opt out of App Transport Security since Apple plans to require App Transport Security starting 1 January 2017.

What Are Domain Exceptions

App Transport Security domain exceptions exempt network requests to a predefined domain from the current App Transport Security configuration. Let me explain what that means.

Predefined Domains

Domain exceptions have a few important limitations. The first limitation is that they are static. You cannot specify a domain exception at runtime. That said, you can specify that subdomains of a domain should also be included in the domain exception.

The second important limitation is one I ran into a few weeks ago. Domain exceptions can only be used for valid domain names. This means, for example, that a static IP address cannot be used to define a domain exception. It is unclear whether this is a bug Apple plans to address. This may change in the future and I hope it does.

Current Configuration

A domain exception is evaluated against the current App Transport Security configuration. What does that mean? If you decide to opt in to App Transport Security, then the domain exception exempts the specified domain from the App Transport Security rules.

If you decide to opt out of App Transport Security, then App Transport Security rules are applied to the domain specified by the domain exception. This is very important to understand. In short, the effect of a domain exception depends on the App Transport Security configuration of the target.

Adding a Domain Exception

Adding a domain exception is easy. You add the NSExceptionDomains key to the NSAppTransportSecurity dictionary of the target's Info.plist. The value of the key is a dictionary with every key of the dictionary being a domain exception. Take a look at the following example for clarification.

<key>NSAppTransportSecurity</key>
<dict>
  <key>NSAllowsArbitraryLoads</key>
  <false/>
  <key>NSExceptionDomains</key>
  <dict>
    <key>cocoacasts.com</key>
    <dict>
      <key>NSIncludesSubdomains</key>
      <true/>
      <key>NSExceptionAllowsInsecureHTTPLoads</key>
      <true/>
    </dict>
  </dict>
</dict>

In this example, we enable App Transport Security and define a domain exception for cocoacasts.com. By setting NSIncludesSubdomains, we tell App Transport Security to apply this domain exception to every subdomain of cocoacasts.com. The NSExceptionAllowsInsecureHTTPLoads key indicates that network requests not made over HTTPS are allowed for this domain and its subdomains.

If we opt out of App Transport Security by setting the value of NSAllowsArbitraryLoads to true, the behavior of the domain exception is different. In that scenario, the App Transport Security rules apply to cocoacasts.com and its subdomains.

Domain Exceptions Keys

App Transport Security imposes a number of rules on an application's network behavior. These rules not only relate to the use of the HTTPS protocol for making network requests, though. They also apply to the configuration of the server your application communicates with. The keys you can use for configuring domain exceptions are listed below.

  • NSIncludesSubdomains
  • NSExceptionAllowsInsecureHTTPLoads
  • NSExceptionRequiresForwardSecrecy
  • NSExceptionMinimumTLSVersion
  • NSThirdPartyExceptionAllowsInsecureHTTPLoads
  • NSThirdPartyExceptionRequiresForwardSecrecy
  • NSThirdPartyExceptionMinimumTLSVersion

You can read more about the use and the possible values of these keys on Apple's developer website.

The following example is a bit more complex. With this example, I want to show you that the configuration can be pretty advanced thanks to the ability to add multiple domain exceptions.

<key>NSAppTransportSecurity</key>
<dict>
  <key>NSAllowsArbitraryLoads</key>
  <false/>
  <key>NSExceptionDomains</key>
  <dict>
    <key>someotherdomain.com</key>
    <dict>
      <key>NSIncludesSubdomains</key>
      <true/>
      <key>NSExceptionMinimumTLSVersion</key>
      <string>TLSv1.0</string>
    </dict>
    <key>codefoundry.be</key>
    <dict>
      <key>NSExceptionRequiresForwardSecrecy</key>
      <false/>
    </dict>
    <key>cocoacasts.com</key>
    <dict>
      <key>NSIncludesSubdomains</key>
      <true/>
      <key>NSExceptionAllowsInsecureHTTPLoads</key>
      <true/>
    </dict>
  </dict>
</dict>

Opting In or Out

Every application built with Xcode 7 or higher has App Transport Security enabled by default. This means that, if you build an application with Xcode 7 or higher, you opt in to App Transport Security unless you configure App Transport Security in the target's Info.plist to fit the application's network behavior.

With the introduction of App Transport Security, Apple has forced developers to consider the network needs and behavior of their applications. This is a good thing. Major players in the technology industry, most notably Apple, Google, and Facebook, are pushing for more security on the web. I am sure you agree that this is a positive trend.

Questions? Leave them in the comments below or reach out to me on Twitter.