I am building a simple iOS app that talks to Firebase using REST API.
Essentially, I am using NSURLSession.sharedSession().dataTaskWithRequest
to connect to
https://myusername.firebaseio.com/Object.json
The app works fine in iOS 8. I am able to pass GET/PUT/PATCH/DELETE to manipulate my data. But since iOS 9 introduced ATS, I now have the https error:
NSURLSession/NSURLConnection HTTP load failed
(kCFStreamErrorDomainSSL, CFNetwork SSLHandshake failed)
I am fully aware of the workaround solution in Info.plist. However, I want to utilize the new safety feature in iOS 9.
I checked Firebase connection security (by clicking on Chrome's green lock button), and it seems to be compatible with Apple's ATS requirement.
Is my error because of the way I use NSURLSession? Or is it because of the Firebase security setup?
PS: I tested https://firebase.com and NSURLSession connects fine w/o error. My app is also simple enough that I don't require auth.
Thank you for your help.
TL;DR: It has to do with the SSL ciphers Firebase servers allow (ATS requires ECDHE only out of the box).
As mentioned, the workaround in Info.plist is to add the following:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>firebaseio.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
</dict>
</dict>
In the ATS docs, Apple only allows for the following out of the box:
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
Setting the NSThirdPartyExceptionRequiresForwardSecrecy
flag to NO
in Info.plist adds the following additional ones:
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
TLS_DHE_RSA_WITH_AES_256_CBC_SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_AES_256_GCM_SHA384
TLS_RSA_WITH_AES_128_GCM_SHA256
TLS_RSA_WITH_AES_256_CBC_SHA256
TLS_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_128_CBC_SHA256
TLS_RSA_WITH_AES_128_CBC_SHA
I disagree with their naming of the flag to be "...ExceptionRequiresForwardSecrecy" since technically DHE provides perfect forward secrecy, it's just slower than the comparable ECDHE versions. Sounds to me like there should be two flags, one being the exception to forward secrecy and one that just says that you're comfortable having a slower handshake.
Technically you could also make the excepted domain <your-firebase-app>.firebaseio.com
and not have the NSIncludesSubdomains
flag, but I wanted to make this sufficiently generic.
Since we allow for non ECDHE ciphers, Firebase would have to disallow them server side for this to work out of the box (unless developers wanted to start messing around with lower level stuff than NSURLRequest, see this SO post for more info on configuring SSL ciphers, but you'll spend more time doing that than adding a few lines to Info.plist).
Security-wise, we're providing comparable versions of the same ciphers, just not using the Elliptic Curves version (which provide a decent performance improvement, but exclude certain browsers [particularly mobile browsers]). More info on DHE vs ECDHE (and some other nice SSL background w.r.t Forward Secrecy is here).
For what it's worth, the realtime clients don't have this problem, so I would strongly recommend using those for a better Firebase experience :)