2016.7.1 | 根据苹果官方文档的修改作出文档的调整,并加入对诊断ATS的命令行工具nscurl进行说明。 |
2015.8.19 | 解决在iOS9下基于ATS对HTTP的请求的说明及适配进行说明 |
iOS9中新增App Transport Security(简称ATS)特性, 主要使到原来请求的时候用到的HTTP,都转向TLS1.2协议进行传输。这也意味着全部的HTTP协议都强制使用了HTTPS协议进行传输。原文以下:html
App Transport Securityios
App Transport Security (ATS) enforces best practices in the secure connections between an app and its back end. ATS prevents accidental disclosure, provides secure default behavior, and is easy to adopt; it is also on by default in iOS 9 and OS X v10.11. 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. In addition, your communication through higher-level APIs needs to be encrypted using TLS version 1.2 with forward secrecy. If you try to make a connection that doesn't follow this requirement, an error is thrown. If your app needs to make a request to an insecure domain, you have to specify this domain in your app's |
若是咱们在iOS9下直接进行HTTP请求是会收到以下错误提示:浏览器
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.安全
系统会告诉咱们不能直接使用HTTP进行请求,须要在Info.plist新增一段用于控制ATS的配置:bash
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>
也即:服务器
这段配置中的NSAppTransportSecurity是ATS配置的根节点,配置了节点表示告诉系统要走自定义的ATS设置。而NSAllowsAritraryLoads节点则是控制是否禁用ATS特性,设置YES就是禁用ATS功能。网络
ATS是在iOS 9.0 和 OS X v10.11版本中增长的特性,使用iOS 9.0或者OS X v10.11的SDK版本(或更新的SDK)进行编译应用时会默认启动ATS。则须要对ATS进行配置。若是使用iOS 9.0或者OS X v10.11以前的SDK版本编译的应用默认是禁止ATS的,所以不会影响应用的网络链接方面的功能(即便在iOS 9.0的机子上跑也是不影响的)。app
直到前面的配置能够完美的适配iOS9了,可是若是你想遵循苹果给出的标准,让本身的数据更加安全,那么须要继续往下看。
其实ATS并不仅仅针对HTTP进行了限制,对HTTPS也有必定的要求,以百度的地址为例(注:举该栗子的时候百度是还没符合ATS的要求的,如今百度已经支持ATS),若是在App中请求https://www.baidu.com的话,是会收到以下的错误信息:
NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)
查阅了一下官方资料(https://developer.apple.com/library/ios/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW33),发现HTTPS的请求须要知足下面的要求:
Requirements for Connecting Using ATSWith ATS fully enabled, your app’s HTTP connections must use HTTPS and must satisfy the following security requirements:
|
根据原文描述,首先颁发给服务器证书的证书机构(CA)的根证书必须是内置于操做系统(哪些根证书被信任能够查看https://support.apple.com/zh-cn/HT205205,或者在你的机子的设置-通用-关于本机最下面的“进一步了解被信任的证书”中查看)或者受用户或者系统管理员信任并安装到操做系统上的。并且必需要基于TLS 1.2版本协议。再来就是链接的加密方式要提供Forward Secrecy(FS正向保密,感兴趣的筒子能够看看这个https://vincent.bernat.im/en/blog/2011-ssl-perfect-forward-secrecy.html),文档中罗列出了支持的加密算法(上面的原文中有说明,我把它独立抽出来放到下面表格中查看)。最后就是证书至少要使用一个SHA256的指纹与任一个2048位或者更高位的RSA密钥,或者是256位或者更高位的ECC密钥。若是不符合其中一项,请求将被中断并返回nil。
支持Forward Secrecy的加密方式
|
咱们再来看刚才的百度的地址,用浏览器打开百度的地址,而后点击连接前面的锁图标,如图:
能够看到它使用了TLS 1.2版本协议,符合上面所说的TLS版本的约定。
而后在点击证书信息,查看颁发给它证书的CA的根证书,如图:
能够看到它的根证书名称是:VeriSign Class 3 Public Primary Certification Authority - G5,根据这个名字在以前提供URL中去寻找iOS9下受信任的根证书是否有存在该证书,结果是能够找到对应的证书信息的,以下图所示:
最后回到以前的链接信息面板能够看到使用AES_128_GCM进行加密,并使用ECDHE_RSA做为密钥交换机制的,咱们能够在Forward Secrecy的列表中找到对应两条记录:
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
可是还不能肯定百度是否提供Forward Secrecy,咱们再点开证书信息,查看“签发者名称”和“公共密钥信息”两项,如图:
看到签名算法中写着“带RSA加密的SHA-1”。能够断定该加密算法不包含在上面两项中。所以百度是一个不符合ATS的要求,因此返回了错误。这时候,若是要解决这样的问题,一样须要对ATS进行配置。配置以下:
<key>NSAppTransportSecurity</key> <dict> <key>NSExceptionDomains</key> <dict> <key>baidu.com</key> <dict> <key>NSIncludesSubdomains</key> <true/> <key>NSExceptionRequiresForwardSecrecy</key> <false/> <key>NSExceptionAllowsInsecureHTTPLoads</key> <true/> </dict> </dict> </dict>
其中NSIncludesSubdomains设置为YES表示百度的子级域名都使用相同设置。NSExceptionRequiresForwardSecrecy为NO因为百度不支持ForwardSecrecy,所以屏蔽掉改功能。最后NSExceptionAllowInsecureHTTPLoads设置为YES,则表示容许访问没有证书或者是自签名、过时、主机名不匹配的证书引起的错误的域名(这里检查过百度的证书貌似没有什么问题,可是仍是须要设置此项才容许访问)。
----------------------------
在最近的测试中因为百度已经支持ATS(昨天@Jolie_Yang给我留言才知道的^_^),而我在不配置任何ATS设置的时候使用NSURLConnection去测试https://www.baidu.com返回的结果仍是报错的。后来,我用NSURLSession去测试该网址发现是能够正常访问。
苹果官方是推荐使用NSURLSession去作HTTP请求的,虽说NSURLConnection一样支持ATS方面的特性,但从我上面的测试来看估计它们二者的默认行为上有些不同,因此若是还在使用NSURLConnection的同窗应该尽早切换到NSURLSession上,避免产生一些没必要要错误。
最后,说到如何诊断一个URL是否支持ATS,这里给你们介绍一些nscurl这个命令行工具,这个工具是OS X v10.11上新增的,主要用于诊断ATS带来的链接问题,利用它能够在命令行中直接检测一个URL地址是否支持ATS。其用法以下:
/usr/bin/nscurl --ats-diagnostics [--verbose] URL
URL - 表示用来诊断的网址
verbose - 该选项将会为每次的链接包含更多信息,包括使用到Info.plist中的哪些key和对应的值也会列出来。
仍是以百度为例,对其https://baidu.com进行诊断,命令以下:
nscurl --ats-diagnostics https://baidu.com
其输出信息以下:
Configuring ATS Info.plist keys and displaying the result of HTTPS loads to https://baidu.com. A test will "PASS" if URLSession:task:didCompleteWithError: returns a nil error. Use '--verbose' to view the ATS dictionaries used and to display the error received in URLSession:task:didCompleteWithError:. ================================================================================ Default ATS Secure Connection --- ATS Default Connection 2016-07-19 17:51:43.156 nscurl[7936:828662] 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. Result : FAIL --- ================================================================================ Allowing Arbitrary Loads --- Allow All Loads Result : PASS --- ================================================================================ Configuring TLS exceptions for baidu.com --- TLSv1.2 Result : FAIL --- --- TLSv1.1 Result : FAIL --- --- TLSv1.0 Result : FAIL --- ================================================================================ Configuring PFS exceptions for baidu.com --- Disabling Perfect Forward Secrecy Result : FAIL --- ================================================================================ Configuring PFS exceptions and allowing insecure HTTP for baidu.com --- Disabling Perfect Forward Secrecy and Allowing Insecure HTTP Result : FAIL --- ================================================================================ Configuring TLS exceptions with PFS disabled for baidu.com --- TLSv1.2 with PFS disabled Result : FAIL --- --- TLSv1.1 with PFS disabled Result : FAIL --- --- TLSv1.0 with PFS disabled Result : FAIL --- ================================================================================ Configuring TLS exceptions with PFS disabled and insecure HTTP allowed for baidu.com --- TLSv1.2 with PFS disabled and insecure HTTP allowed Result : FAIL --- --- TLSv1.1 with PFS disabled and insecure HTTP allowed Result : FAIL --- --- TLSv1.0 with PFS disabled and insecure HTTP allowed Result : FAIL --- ================================================================================
能够看到除了Allowing Arbitrary Loads一项的Result是Pass,其余的Result都是FAIL,那这证实了baidu.com尚未支持ATS,可是从它的证书来看是已经支持的了,为了了解更详细的信息,咱们把verbose选项加入再进行诊断一下,来了解更多的信息,命令以下:
nscurl --ats-diagnostics --verbose https://baidu.com
其信息输出以下:
vimfungdeMac-mini:~ vimfung$ nscurl --ats-diagnostics --verbose https://baidu.com Starting ATS Diagnostics Configuring ATS Info.plist keys and displaying the result of HTTPS loads to https://baidu.com. A test will "PASS" if URLSession:task:didCompleteWithError: returns a nil error. ================================================================================ Default ATS Secure Connection --- ATS Default Connection ATS Dictionary: { } 2016-07-19 17:57:24.887 nscurl[7971:833843] 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. Result : FAIL Error : Error Domain=NSURLErrorDomain Code=-1022 "The resource could not be loaded because the App Transport Security policy requires the use of a secure connection." UserInfo={NSUnderlyingError=0x7fac41703970 {Error Domain=kCFErrorDomainCFNetwork Code=-1022 "(null)"}, NSErrorFailingURLStringKey=http://www.baidu.com/, NSErrorFailingURLKey=http://www.baidu.com/, NSLocalizedDescription=The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.} --- ================================================================================ Allowing Arbitrary Loads --- Allow All Loads ATS Dictionary: { NSAllowsArbitraryLoads = true; } Result : PASS --- ================================================================================ Configuring TLS exceptions for baidu.com --- TLSv1.2 ATS Dictionary: { NSExceptionDomains = { "baidu.com" = { NSExceptionMinimumTLSVersion = "TLSv1.2"; }; }; } Result : FAIL Error : Error Domain=NSURLErrorDomain Code=-1022 "The resource could not be loaded because the App Transport Security policy requires the use of a secure connection." UserInfo={NSUnderlyingError=0x7fac4164cc20 {Error Domain=kCFErrorDomainCFNetwork Code=-1022 "(null)"}, NSErrorFailingURLStringKey=http://www.baidu.com/, NSErrorFailingURLKey=http://www.baidu.com/, NSLocalizedDescription=The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.} --- --- TLSv1.1 ATS Dictionary: { NSExceptionDomains = { "baidu.com" = { NSExceptionMinimumTLSVersion = "TLSv1.1"; }; }; } Result : FAIL Error : Error Domain=NSURLErrorDomain Code=-1022 "The resource could not be loaded because the App Transport Security policy requires the use of a secure connection." UserInfo={NSUnderlyingError=0x7fac4143dfc0 {Error Domain=kCFErrorDomainCFNetwork Code=-1022 "(null)"}, NSErrorFailingURLStringKey=http://www.baidu.com/, NSErrorFailingURLKey=http://www.baidu.com/, NSLocalizedDescription=The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.} --- --- TLSv1.0 ATS Dictionary: { NSExceptionDomains = { "baidu.com" = { NSExceptionMinimumTLSVersion = "TLSv1.0"; }; }; } Result : FAIL Error : Error Domain=NSURLErrorDomain Code=-1022 "The resource could not be loaded because the App Transport Security policy requires the use of a secure connection." UserInfo={NSUnderlyingError=0x7fac4143e480 {Error Domain=kCFErrorDomainCFNetwork Code=-1022 "(null)"}, NSErrorFailingURLStringKey=http://www.baidu.com/, NSErrorFailingURLKey=http://www.baidu.com/, NSLocalizedDescription=The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.} --- ================================================================================ Configuring PFS exceptions for baidu.com --- Disabling Perfect Forward Secrecy ATS Dictionary: { NSExceptionDomains = { "baidu.com" = { NSExceptionRequiresForwardSecrecy = false; }; }; } Result : FAIL Error : Error Domain=NSURLErrorDomain Code=-1022 "The resource could not be loaded because the App Transport Security policy requires the use of a secure connection." UserInfo={NSUnderlyingError=0x7fac414358c0 {Error Domain=kCFErrorDomainCFNetwork Code=-1022 "(null)"}, NSErrorFailingURLStringKey=http://www.baidu.com/, NSErrorFailingURLKey=http://www.baidu.com/, NSLocalizedDescription=The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.} --- ================================================================================ Configuring PFS exceptions and allowing insecure HTTP for baidu.com --- Disabling Perfect Forward Secrecy and Allowing Insecure HTTP ATS Dictionary: { NSExceptionDomains = { "baidu.com" = { NSExceptionAllowsInsecureHTTPLoads = true; NSExceptionRequiresForwardSecrecy = false; }; }; } Result : FAIL Error : Error Domain=NSURLErrorDomain Code=-1022 "The resource could not be loaded because the App Transport Security policy requires the use of a secure connection." UserInfo={NSUnderlyingError=0x7fac416589a0 {Error Domain=kCFErrorDomainCFNetwork Code=-1022 "(null)"}, NSErrorFailingURLStringKey=http://www.baidu.com/, NSErrorFailingURLKey=http://www.baidu.com/, NSLocalizedDescription=The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.} --- ================================================================================ Configuring TLS exceptions with PFS disabled for baidu.com --- TLSv1.2 with PFS disabled ATS Dictionary: { NSExceptionDomains = { "baidu.com" = { NSExceptionMinimumTLSVersion = "TLSv1.2"; NSExceptionRequiresForwardSecrecy = false; }; }; } Result : FAIL Error : Error Domain=NSURLErrorDomain Code=-1022 "The resource could not be loaded because the App Transport Security policy requires the use of a secure connection." UserInfo={NSUnderlyingError=0x7fac41633bf0 {Error Domain=kCFErrorDomainCFNetwork Code=-1022 "(null)"}, NSErrorFailingURLStringKey=http://www.baidu.com/, NSErrorFailingURLKey=http://www.baidu.com/, NSLocalizedDescription=The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.} --- --- TLSv1.1 with PFS disabled ATS Dictionary: { NSExceptionDomains = { "baidu.com" = { NSExceptionMinimumTLSVersion = "TLSv1.1"; NSExceptionRequiresForwardSecrecy = false; }; }; } Result : FAIL Error : Error Domain=NSURLErrorDomain Code=-1022 "The resource could not be loaded because the App Transport Security policy requires the use of a secure connection." UserInfo={NSUnderlyingError=0x7fac414625e0 {Error Domain=kCFErrorDomainCFNetwork Code=-1022 "(null)"}, NSErrorFailingURLStringKey=http://www.baidu.com/, NSErrorFailingURLKey=http://www.baidu.com/, NSLocalizedDescription=The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.} --- --- TLSv1.0 with PFS disabled ATS Dictionary: { NSExceptionDomains = { "baidu.com" = { NSExceptionMinimumTLSVersion = "TLSv1.0"; NSExceptionRequiresForwardSecrecy = false; }; }; } Result : FAIL Error : Error Domain=NSURLErrorDomain Code=-1022 "The resource could not be loaded because the App Transport Security policy requires the use of a secure connection." UserInfo={NSUnderlyingError=0x7fac41464e40 {Error Domain=kCFErrorDomainCFNetwork Code=-1022 "(null)"}, NSErrorFailingURLStringKey=http://www.baidu.com/, NSErrorFailingURLKey=http://www.baidu.com/, NSLocalizedDescription=The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.} --- ================================================================================ Configuring TLS exceptions with PFS disabled and insecure HTTP allowed for baidu.com --- TLSv1.2 with PFS disabled and insecure HTTP allowed ATS Dictionary: { NSExceptionDomains = { "baidu.com" = { NSExceptionAllowsInsecureHTTPLoads = true; NSExceptionMinimumTLSVersion = "TLSv1.2"; NSExceptionRequiresForwardSecrecy = false; }; }; } Result : FAIL Error : Error Domain=NSURLErrorDomain Code=-1022 "The resource could not be loaded because the App Transport Security policy requires the use of a secure connection." UserInfo={NSUnderlyingError=0x7fac41468d40 {Error Domain=kCFErrorDomainCFNetwork Code=-1022 "(null)"}, NSErrorFailingURLStringKey=http://www.baidu.com/, NSErrorFailingURLKey=http://www.baidu.com/, NSLocalizedDescription=The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.} --- --- TLSv1.1 with PFS disabled and insecure HTTP allowed ATS Dictionary: { NSExceptionDomains = { "baidu.com" = { NSExceptionAllowsInsecureHTTPLoads = true; NSExceptionMinimumTLSVersion = "TLSv1.1"; NSExceptionRequiresForwardSecrecy = false; }; }; } Result : FAIL Error : Error Domain=NSURLErrorDomain Code=-1022 "The resource could not be loaded because the App Transport Security policy requires the use of a secure connection." UserInfo={NSUnderlyingError=0x7fac4146a6e0 {Error Domain=kCFErrorDomainCFNetwork Code=-1022 "(null)"}, NSErrorFailingURLStringKey=http://www.baidu.com/, NSErrorFailingURLKey=http://www.baidu.com/, NSLocalizedDescription=The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.} --- --- TLSv1.0 with PFS disabled and insecure HTTP allowed ATS Dictionary: { NSExceptionDomains = { "baidu.com" = { NSExceptionAllowsInsecureHTTPLoads = true; NSExceptionMinimumTLSVersion = "TLSv1.0"; NSExceptionRequiresForwardSecrecy = false; }; }; } Result : FAIL Error : Error Domain=NSURLErrorDomain Code=-1022 "The resource could not be loaded because the App Transport Security policy requires the use of a secure connection." UserInfo={NSUnderlyingError=0x7fac416932b0 {Error Domain=kCFErrorDomainCFNetwork Code=-1022 "(null)"}, NSErrorFailingURLStringKey=http://www.baidu.com/, NSErrorFailingURLKey=http://www.baidu.com/, NSLocalizedDescription=The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.} --- ================================================================================
能够看到了更多的信息,包括了Info.plist中的配置项和请求的错误描述信息。其中发现当请求https://baidu.com的时候,它会报NSErrorFailingURLKey=http://www.baidu.com。因此,我估计是百度对这个网址进行了跳转,而跳转到的地址就是http://www.baidu.com,因此不可靠的HTTP链接都被ATS被拦截了,才会出现Fail的结果。
所以,我尝试换了https://www.baidu.com再次进行测试,其输入结果以下:
vimfungdeMac-mini:~ vimfung$ nscurl --ats-diagnostics --verbose https://www.baidu.com Starting ATS Diagnostics Configuring ATS Info.plist keys and displaying the result of HTTPS loads to https://www.baidu.com. A test will "PASS" if URLSession:task:didCompleteWithError: returns a nil error. ================================================================================ Default ATS Secure Connection --- ATS Default Connection ATS Dictionary: { } Result : PASS --- ================================================================================ Allowing Arbitrary Loads --- Allow All Loads ATS Dictionary: { NSAllowsArbitraryLoads = true; } Result : PASS --- ================================================================================ Configuring TLS exceptions for www.baidu.com --- TLSv1.2 ATS Dictionary: { NSExceptionDomains = { "www.baidu.com" = { NSExceptionMinimumTLSVersion = "TLSv1.2"; }; }; } Result : PASS --- --- TLSv1.1 ATS Dictionary: { NSExceptionDomains = { "www.baidu.com" = { NSExceptionMinimumTLSVersion = "TLSv1.1"; }; }; } Result : PASS --- --- TLSv1.0 ATS Dictionary: { NSExceptionDomains = { "www.baidu.com" = { NSExceptionMinimumTLSVersion = "TLSv1.0"; }; }; } Result : PASS --- ================================================================================ Configuring PFS exceptions for www.baidu.com --- Disabling Perfect Forward Secrecy ATS Dictionary: { NSExceptionDomains = { "www.baidu.com" = { NSExceptionRequiresForwardSecrecy = false; }; }; } Result : PASS --- ================================================================================ Configuring PFS exceptions and allowing insecure HTTP for www.baidu.com --- Disabling Perfect Forward Secrecy and Allowing Insecure HTTP ATS Dictionary: { NSExceptionDomains = { "www.baidu.com" = { NSExceptionAllowsInsecureHTTPLoads = true; NSExceptionRequiresForwardSecrecy = false; }; }; } Result : PASS --- ================================================================================ Configuring TLS exceptions with PFS disabled for www.baidu.com --- TLSv1.2 with PFS disabled ATS Dictionary: { NSExceptionDomains = { "www.baidu.com" = { NSExceptionMinimumTLSVersion = "TLSv1.2"; NSExceptionRequiresForwardSecrecy = false; }; }; } Result : PASS --- --- TLSv1.1 with PFS disabled ATS Dictionary: { NSExceptionDomains = { "www.baidu.com" = { NSExceptionMinimumTLSVersion = "TLSv1.1"; NSExceptionRequiresForwardSecrecy = false; }; }; } Result : PASS --- --- TLSv1.0 with PFS disabled ATS Dictionary: { NSExceptionDomains = { "www.baidu.com" = { NSExceptionMinimumTLSVersion = "TLSv1.0"; NSExceptionRequiresForwardSecrecy = false; }; }; } Result : PASS --- ================================================================================ Configuring TLS exceptions with PFS disabled and insecure HTTP allowed for www.baidu.com --- TLSv1.2 with PFS disabled and insecure HTTP allowed ATS Dictionary: { NSExceptionDomains = { "www.baidu.com" = { NSExceptionAllowsInsecureHTTPLoads = true; NSExceptionMinimumTLSVersion = "TLSv1.2"; NSExceptionRequiresForwardSecrecy = false; }; }; } Result : PASS --- --- TLSv1.1 with PFS disabled and insecure HTTP allowed ATS Dictionary: { NSExceptionDomains = { "www.baidu.com" = { NSExceptionAllowsInsecureHTTPLoads = true; NSExceptionMinimumTLSVersion = "TLSv1.1"; NSExceptionRequiresForwardSecrecy = false; }; }; } Result : PASS --- --- TLSv1.0 with PFS disabled and insecure HTTP allowed ATS Dictionary: { NSExceptionDomains = { "www.baidu.com" = { NSExceptionAllowsInsecureHTTPLoads = true; NSExceptionMinimumTLSVersion = "TLSv1.0"; NSExceptionRequiresForwardSecrecy = false; }; }; } Result : PASS --- ================================================================================
输出的结果都是Pass的了,那证实百度仍是支持ATS的。好了,这是我最新对ATS的研究,但愿对你们有用。