iOS 9 SSL Issues
If like us you have an iOS app that delegates the login process to a web-based authentication flow (or uses an external API) you might have had unexpected issues when developing/running your apps on iOS 9. If those issues are related to SSL errors, read on:
We have a native iOS mobile app that we developed that authenticates using a web-based authentication flow - the same flow as is used by our web app. Our users come from many different educational institutions, each of which has its own authentication provider. We’ve configured our login flow to allow us to configure the authentication provider appropriately for each institution - meaning if you come from “institution A” you’ll authenticate differently to a user coming from “institution B”.
The mobile app supports the same mechanism for login such that once a user selects their institution from a list, they will be presented with their own institutions login flow and would login using their own institutional user/password.
This all worked fine until iOS 9 came along…
iOS 9 and “ATS” - App Transport Security
With iOS 9, Apple ensured that App Transport Security was enabled by default. In a nutshell, this meant that well-behaved apps would use best practices for communicating between the app and the back end services. Essentially, you should be communicating over HTTPS and using TLS version 1.2 with (crucially) “forward secrecy” setup correctly.
Let the problems begin…
It all started with a report that one of our customers could not login via the mobile app any more - having been able to do so previously.
Investigation of the iOS app showed that this error was being generated:
NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)
Looking up this error suggested it was related to the previously mentioned “forward secrecy”.
Examining SSL certificates
By using Chrome’s developer tools and capturing the network traffic generated during the login flow for that specific institution, the servers partaking in the sign in process where identified.
Then the SSL certificates where examined using the amazingly useful online tool located at SSLLabs which gave us a clue as to were the problem lay.
The 2 server’s certificates were graded C and F by the SSLLabs analysis, the worst offender being:
Note the highlighted forward secrecy result:
The problem lies with the fact that TLS 1.2 is not supported and the forward secrecy element reports that it is not supported on modern reference browsers.
This is putting aside the fact that the certificate as a whole is graded F and is still potentially vulnerable to some old attacks.
There are a few solutions to this issue - the first and most correct is to sort out the server with the F grade SSL certificate so that it is not only more secure and less vulnerable to attacks but so that our iOS 9 applications can communicate without issue.
Another solution is one where you have to think carefully about what you are doing: you can update your iOS application to allow less secure communications by disabling App Transport Security for all traffic, or for selected domains but is this what you want to do?
If you take this route, you must consider it a temporary solution only, and consider very carefully what you may be exposing your application, servers and users to.
We strongly advise you read iOS 9 Changes, especially the section on “App Transport Security”.
Done that? Then proceed with caution!
Consider your specific scenario and choose an approach with care:
ATS ON, but disabled for selected domains
An option which is a compromise is to keep ATS switched on, but disabled for selected domains - this may work well for you if you have a defined list of domains that is already known to you and which causes your application to fail.
If not, it could start to get very tedious rebuilding and re-submitting your app each time a new server is found to be non-compliant.
Configure your Info.plist like this, adding in entries for the servers you want to exclude from ATS:
ATS OFF, but enabled for selected domains
If you don’t know which servers may cause you an issue, but you do know which ones won’t, then you could choose to disable ATS for all but a specific set of domains - essentially the opposite to the above, but potentially less secure.
Configure your Info.plist like this, adding in entries for the servers you want to include for ATS:
Switch off ATS completely
Finally, the equivalent of an atom bomb to your security - disable ATS completely for all domains. Unfortunately this is the easiest to configure in your application yet should be considered the last resort.
Configure your Info.plist with the following:
i.e. add this:
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>
In conclusion, when working with native apps on iOS 9 you must consider the security of your back end servers that take part in any authentication flow or provide a business API. If the servers that partake in those processes are under your control, you have no reason not to resolve SSL certificate errors yourself and make the entire process more secure.
However if the servers are outside of your control and getting SSL certificates changed is not an easy task, you do have options open to you, but they are ones you must consider very carefully.