Using Charles Proxy to debug HTTPS requests on an iOS 9 simulator now has extra step to get it up and running. Application Transport Security (ATS) is the new technology in iOS 9 (and OS X v10.11) to enforce a set of best practices for all connections between an app and its backend. In practice, it blocks HTTP requests and some HTTPS requests that don’t meet a minimum standard, unless you provide an exception in your Info.plist. Currently, it also seems to be blocking requests when Charles is acting as a proxy for debugging purposes.

To continue to use Charles, we have to explicitly allow Insecure HTTP Loads in the Info.plist for requests on our domain to be readable in Charles. This covers (inherently) insecure HTTP connections and HTTPS connections that are not secure enough. The current beta of iOS 9 qualifies proxying through Charles as not secure, which is why we need the exception.

To do this, starting out on a fresh simulator, we’ll need to install the Charles Root Certificate

We’ll still be seeing those SSL Handshake failures. Next, we need to add the exception in our Info.plist under a new NSAppTransportSecurity dict

[code language=”xml”]

<key>NSAppTransportSecurity</key>

<dict>

<key>NSExceptionDomains</key>

<dict>

<key>reverb.com</key>

<dict>

<key>NSIncludesSubdomains</key>

<true/>

<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>

<true/>

</dict>

</dict>

</dict>

[/code]

However, as Apple has telegraphed, exceptions shouldn’t be used unless absolutely necessary. Ideally, we’d only include this exception on DEBUG builds. To accomplish this, we can use a Run Script Phase under Build Phases. Using PlistBuddy, a command line tool preinstalled on OS X for directly reading and modifying values inside a property list, we can edit the build’s copy of the Info.plist to include the exception only when we need to. Since it is changing the build’s copy, these exceptions will only be available on that Debug build, leaving your Info.plist and its own list of exceptions alone. This also means these changes won’t be checked into version control.

Go to TARGETS->App->Build Phases then click on the plus sign in the upper left and select ‘New Run Script Phase’. Paste in the script below, changing the domain values as needed.

[code language=”bash”]

# Add exception for Debug builds

if [ “${CONFIGURATION}” == “Debug” ]

then

# Remove exception existing builds

/usr/libexec/PlistBuddy -c “Delete :NSAppTransportSecurity:NSExceptionDomains:reverb.com” “${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}” 2>/dev/null

exitCode=$? #Supresses failure

/usr/libexec/PlistBuddy -c “Add :NSAppTransportSecurity:NSExceptionDomains:reverb.com dict” “${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}”

/usr/libexec/PlistBuddy -c “Add :NSAppTransportSecurity:NSExceptionDomains:reverb.com:NSIncludesSubdomains bool true” “${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}”

/usr/libexec/PlistBuddy -c “Add :NSAppTransportSecurity:NSExceptionDomains:reverb.com:NSTemporaryExceptionAllowsInsecureHTTPLoads bool true” “${CONFIGURATION_BUILD_DIR}/${INFOPLIST_PATH}”

fi

[/code]

This workaround is valid as of iOS 9 Beta 6. Things could change in the future to make this unnecessary. I’ll attempt to keep this post updated if anything changes. Edit: This continues to be necessary through the iOS 9 release, so I think it is safe to say it is here to stay.

For more info on using NSAppTransportSecurity exceptions in general, Steven Peterson has an excellent blog post: http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/

Kevin Donnelly

Senior Mobile Developer

@donnellyk