In the past you might have used 3rd party libraries like TrustKit or Alamofire to protect your app from man-in-the-middle attacks because those libraries support SSL public key pinning.
You might not know this but Apple introduced native support for SSL public key pinning in iOS 14 π₯³
If you are not familiar with this native capability I recommend reading Apple's article Identity Pinning: How to configure server certificates for your app. Here is a summary:
- You can specify a collection of certificates in your
Info.plist
that App Transport Security (ATS) expects when connecting to named domains. - A pinned CA public key must appear in either an intermediate or root certificate in a certificate chain
- Pinned keys are always associated with a domain name, and the app will refuse to connect to that domain unless the pinning requirement is met.
- You can associate multiple public keys with a domain name.
This built-in pinning works well for URLSession
but does it work for all APIs on top of CFNetwork
?
The sad truth is no. π
WKWebView
will still connect and load content from the domain if the SSL public key deviates from the one specified in Info.plist
.
SFSafariViewController
does not honor the settings in Info.plist
as well. This behavior might be less surprising considering that SFSafariViewController
runs in a separate process.
I tested those APIs on various releases, including the most recent iOS 15.4.
You can verify my observation with a test app I open-sourced.
Apple's answer is unsatisfying as it is not clear which APIs are expected to honor the certificates specified in Info.plist
.
I believe that SSL pinning based on NSPinnedDomains
should work automatically with all CFNetwork based APIs like
URLSession
WKWebView
.SFSafariViewController
ASWebAuthenticationSession
Maybe one day....