Tuesday, 29 September 2015

App Transport Security (ATS) and iOS 9 HTTP Connection error "The operation couldn’t be completed"

In 2015, With the launch of iOS 9 and OSX  El Capitan apple disabled all unsecured HTTP traffic from iOS apps and comes with new privacy feature called App Transport Security (ATS) to enforce best practices in secure connections between an app and its back end.

All iOS 9 devices running apps built with Xcode 7 that don’t disable ATS will be affected by this change and if app try to make HTTP requests with ATS enabled (iOS 9 and above), we will see the errors like this:

Error Domain=NSURLErrorDomain Code=-1004 "Could not connect to the server." UserInfo=0x12ed5bad0 {NSUnderlyingError=0x12ee495b0 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error -1004.)"

OR

NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)

Before finding the solution to resolve this error we should know about ATS and why apple recommend this .

What is ATS and Why Apple pushing it as default from iOS 9?

According to apple “ App Transport Security (ATS) lets an app add a declaration to its Info.plist file that specifies the domains with which it needs secure communication. ATS prevents accidental disclosure, provides secure default behavior, and is easy to adopt. 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.“

Simply, App Transport Security is a feature that improves the security of connections between an app and web services. The feature consists of default connection requirements that conform to best practices for secure connections.

The reason why Apple is pushing so aggressively to force secure connections is because it’s the right thing to do. Protecting personal data from being compromised over insecure wireless connections, among other things, is great for users.


Requirement to adopt ATS :

App Transport Security is enabled by default when using NSURLSession, NSURLConnection, or CFURL in iOS 9 or OS X El Capitan.

App Transport Security requirements:

 * The server must support at least Transport Layer Security (TLS) protocol version 1.2.

 * Connection ciphers are limited to those that provide forward secrecy (see the list of ciphers below.)

 * Certificates must be signed using a SHA256 or greater signature hash algorithm, with either a 2048-bit or greater RSA key or a 256-bit or greater Elliptic-Curve (ECC) key.Invalid certificates result in a hard failure and no connection.


If your application attempts to connect to any HTTP server that doesn’t support the latest SSL technology (TLSv1.2), your connections will fail with an error like this:

Error Domain=NSURLErrorDomain Code=-1004 "Could not connect to the server." UserInfo=0x12ed5bad0 {NSUnderlyingError=0x12ee495b0 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error -1004.)"

OR

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.


How to Bypass App Transport Security:

ATS is good for you and your users and you shouldn’t disable it, but there are the way for developers to override this default behavior and turn off transport security as per the app requirement. To disable ATS you need to Open Info.plist, and add the following lines:

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


Your info.plist must be look like this.




Per-Domain Exceptions:

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.

Add this code to your info.plist source file.


<key>NSAppTransportSecurity</key>
    <dict>
        <key>NSExceptionDomains</key>
        <dict>
            <key>server1.com</key>
            <dict>
                <!--Include to allow subdomains-->
                <key>NSIncludesSubdomains</key>
                <true/>
                <!--Include to allow HTTP requests-->
                <key>NSExceptionAllowsInsecureHTTPLoads</key>
                <true/>
                <!--Include to specify minimum TLS version-->
                <key>NSExceptionMinimumTLSVersion</key>
                <string>TLSv1.1</string>
            </dict>
            <key>server2.com</key>
            <dict>
                <!--Include domain support forward secrecy using ciphers-->
                <key>NSExceptionRequiresForwardSecrecy</key>
                <true/>
                <!--Include to allow HTTP requests-->
                <key>NSExceptionAllowsInsecureHTTPLoads</key>
                <false/>
            </dict>
        </dict>
    </dict>

Your structured info.plist source file looks like this.



And your info.plist looks like this :




Now, You can see ATS is good for app developers and app users as it improves the security of connections between an app and web services, but you can override it.