iOS 9 和 OS X Captian 带来了一个新的安全特性,也就是 App Transport Security,加强了应用中所谓网络连接的安全性。下面是 ATS 默认的安全要求:
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 better 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.
如果你的应用中使用到的网络链接 (比如请求服务器的 API)不符合以上要求,请求就会失败。那如何检测你的应用是否符合 ATS 的默认要求呢?可以在终端运行 nscurl --verbose --ats-diagnostics + url
, 比如 nscurl --verbose --ats-diagnostics http://www.baidu.com
, 可以看到第一条数据显示:
Default ATS Secure Connection --- ATS Default Connection ATS Dictionary: { } 2015-09-13 13:08:37.117 nscurl[2290:248743] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802) Result : FAIL Error : Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={NSURLErrorFailingURLPeerTrustErrorKey=<SecTrust 0x7fc159e16e60 [0x7fff786a1890]>, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, NSErrorPeerCertificateChainKey=( "<SecCertificate 0x7fc159e15a60 [0x7fff786a1890]>", "<SecCertificate 0x7fc159e164a0 [0x7fff786a1890]>", "<SecCertificate 0x7fc159e167e0 [0x7fff786a1890]>" ), NSUnderlyingError=0x7fc159e26170 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, kCFStreamPropertySSLPeerTrust=<SecTrust 0x7fc159e16e60 [0x7fff786a1890]>, _kCFNetworkCFStreamSSLErrorOriginalValue=-9802, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9802, kCFStreamPropertySSLPeerCertificates=( "<SecCertificate 0x7fc159e15a60 [0x7fff786a1890]>", "<SecCertificate 0x7fc159e164a0 [0x7fff786a1890]>", "<SecCertificate 0x7fc159e167e0 [0x7fff786a1890]>" )}}, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey=https://www.baidu.com/, NSErrorFailingURLStringKey=https://www.baidu.com/, NSErrorClientCertificateStateKey=0} ---
这说明 www.baidu.com 是不符合 ATS 的默认要求的,在 iOS 9 中如果你用一个 NSURLSession 去请求 www.baidu.com, 可以得到一堆错误信息以及返回一个为 nil 的 data.
当然,现在绝大多数的网站和 API 服务都不符合 ATS 的默认要求,可以用以下方法禁用掉 ATS, 打开应用的 Info.plist (用源码的形式打开), 加入一个 entry:
<key>NSAppTransportSecurity</key> <dict> <!--Include to allow all connections (DANGER)--> <key>NSAllowsArbitraryLoads</key> <true/> </dict>
这样就搞定了, 不过从长远来看,还是应该让服务器升级去满足 ATS 的安全要求