原文地址: https://github.com/ChenYilong/iOS9AdaptationTips
关于App Transport Security,每个应用都属于4个大类当中的一类。我们来看看每一个大类都是怎样影响应用的。
-- | 分类名 | 解释 |
---|---|---|
1. | HTTPS Only (只有HTTPS,所有情况下都使用ATS) | 如果你的应用只基于支持HTTPS的服务器,你的应用不需要做任何改变。但是,注意App Transport Security要求TLS 1.2,而且它要求站点使用支持forward secrecy协议的密码。证书也要求是符合ATS规格的。因此慎重检查与你的应用交互的服务器是不是符合ATS的要求。 |
2. | Mix & Match(混合) | 如果你的服务器不符合ATS要求,你需要在你的应用的 Info.plist 文件中说明哪些地址是不符合ATS要求的。 |
3. | Opt Out(禁用ATS) | 如果你在创建一个网页浏览器,因为你不能确定用户将要访问哪个网页,也就不可能指明这些网页是否支持ATS要求且在HTTPS上传输。在这种情况下,只能配置为禁用ATS。 |
4. | Opt Out With Exceptions(除特殊情况外,都不使用ATS) | 如果想禁用ATS的同时又想定义一些例外。这个应用场景是当你的应用需要从很多不符合ATS要求的服务器上取数据,但是也要与一个你可控的API(符合ATS要求)交互。在这种情况下,需要在应用的 Info.plist 文件中配置为允许所有请求,但是你也指定了一个或多个例外来表明哪些请求是必须符合ATS的要求。 |
下面分别做一下介绍:
1.HTTPS Only (只有HTTPS,所有情况下都使用ATS)
如果你的应用只基于支持HTTPS的服务器,那么你太幸运了。你的应用不需要做任何改变。
唯一需要做的事情就是使用 NSURLSession
。如果你的开发目标是iOS 9或者 OS X EI Capitan之后,ATS 的最佳实践将会应用到所有基于 NSURLSession
的网络。
但也有人遇到过这样的疑惑:服务器已支持TLS 1.2 SSL ,但iOS9上还是不行,还要进行本文提出的适配操作。
那是因为:要注意 App Transport Security 要求 TLS 1.2,而且它要求站点使用支持forward secrecy协议的密码。证书也要求是符合ATS规格的,ATS只信任知名CA颁发的证书,小公司所使用的 self signed certificate,还是会被ATS拦截。因此慎重检查与你的应用交互的服务器是不是符合ATS的要求非常重要。对此,建议使用下文中给出的NSExceptionDomains,并将你们公司的域名挂在下面。
官方文档 App Transport Security Technote 对CA颁发的证书要求:
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
2.Mix & Match(混合)
如果你的服务器不符合ATS要求。
比如当你遇到以下三个不符合 ATS 要求的服务器的域名时:
- api.insecuredomain.com
- cdn.domain.com
- thatotherdomain.com
你可以分别设置如下:
-
api.insecuredomain.com
Info.plist 配置中的XML源码如下所示:
<key>NSAppTransportSecurity</key> <dict> <key>NSExceptionDomains</key> <dict> <key>api.insecuredomain.com</key> <dict> <!--允许App进行不安全的HTTP请求--> <key>NSExceptionAllowsInsecureHTTPLoads</key> <true/> <!--适用于这个特定域名下的所有子域--> <key>NSIncludesSubdomains</key> <true/> </dict> </dict> </dict>
在 plist 文件里显示如下:
我们定义的第一个“例外”(Exception)告诉ATS当与这个子域交互的时候撤销了必须使用HTTPS的要求。注意这个仅仅针对在“例外”(Exception)中声明了的子域。非常重要的一点是要理解NSExceptionAllowsInsecureHTTPLoads关键字并不仅仅只是与使用HTTPS相关。这个“例外”(Exception)指明了对于那个域名,所有的App Transport Security的要求都被撤销了。
-
cdn.domain.com Info.plist 配置中的XML源码如下所示:
<key>NSAppTransportSecurity</key> <dict> <key>NSExceptionDomains</key> <dict> <key>cdn.somedomain.com</key> <dict> <key>NSThirdPartyExceptionMinimumTLSVersion</key> <string>TLSv1.1</string> </dict> </dict> </dict>
在 plist 文件里显示如下:
很可能你的应用是与一个支持HTTPS传输数据的服务器交互,但是并没有使用TLS 1.2或更高。在这种情况下,你定义一个“例外”(Exception),它指明应该使用的最小的TLS的版本。这比完全撤销那个域名的App Transport Security要更好更安全。
-
thatotherdomain.com
Info.plist 配置中的XML源码如下所示:
<key>NSAppTransportSecurity</key> <dict> <key>NSExceptionDomains</key> <dict> <key>thatotherdomain.com</key> <dict> <!--适用于这个特定域名下的所有子域--> <key>NSIncludesSubdomains</key> <true/> <!--扩展可接受的密码列表:这个域名可以使用不支持 forward secrecy 协议的密码--> <key>NSExceptionRequiresForwardSecrecy</key> <false/> <!--允许App进行不安全的HTTP请求--> <key>NSExceptionAllowsInsecureHTTPLoads</key> <true/> <!--在这里声明所支持的 TLS 最低版本--> <key>NSExceptionMinimumTLSVersion</key> <string>TLSv1.1</string> </dict> </dict> </dict>
在 plist 文件里显示如下:
NSIncludesSubdomains
关键字告诉 App Transport Security 这个“例外”(Exception)适用于这个特定域名的所有子域。这个“例外”(Exception)还进一步通过扩展可接受的密码列表来定义这个域名可以使用不支持forward secrecy(NSExceptionRequiresForwardSecrecy
) 协议的密码。想了解更多关于forward secrecy的信息,推荐去看官方文档 Apple's technote 。
如果你的App中同时用到了这三个域名,那么应该是这样:
<key>NSAppTransportSecurity</key> <dict> <key>NSExceptionDomains</key> <dict> <key>api.insecuredomain.com</key> <dict> <key>NSExceptionAllowsInsecureHTTPLoads</key> <false/> </dict> <key>cdn.somedomain.com</key> <dict> <key>NSThirdPartyExceptionMinimumTLSVersion</key> <string>TLSv1.1</string> </dict> <key>thatotherdomain.com</key> <dict> <key>NSIncludesSubdomains</key> <true/> <key>NSExceptionRequiresForwardSecrecy</key> <false/> </dict> </dict> </dict>
3. Opt Out(禁用ATS)
上面是比较严谨的做法,指定了能访问哪些特定的HTTP。当然也有暴力的做法: 彻底倒退回不安全的HTTP网络请求,能任意进行HTTP请求,比如你在开发一款浏览器App,或者你想偷懒,或者后台想偷懒,或者公司不给你升级服务器。。。
你可以在Info.plist 配置中改用下面的XML源码:
<key>NSAppTransportSecurity</key> <dict> <!--彻底倒退回不安全的HTTP网络请求,能任意进行HTTP请求 (不建议这样做)--> <key>NSAllowsArbitraryLoads</key> <true/> </dict>
在 plist 文件里显示如下:
4. Opt Out With Exceptions(除特殊情况外,都不使用ATS)
上面已经介绍了三种情景,还有一种可能你也会遇到:
当你禁用ATS的同时又想定义一些“例外”(Exception)。这个应用场景是当你的应用需要从很多不符合ATS要求的服务器上取数据,但是也要与一个你可控的API(符合ATS要求)交互。在这种情况下,在应用的Info.plist文件中配置为允许所有请求,但是你也指定了一个或多个“例外”(Exception)来表明哪些地址是必须符合 App Transport Security 要求的。下面是Info.plist文件应该会有的内容:
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> <key>NSExceptionDomains</key> <dict> <key>api.tutsplus.com</key> <dict> <key>NSExceptionAllowsInsecureHTTPLoads</key> <false/> </dict> </dict> </dict>
在 plist 文件里显示如下:
Certificate Transparency
虽然ATS大多数安全特性都是默认可用的,Certificate Transparency 是必须设置的。如果你有支持Certificate Transparency的证书,你可以检查NSRequiresCertificateTransparency关键字来使用Certificate Transparency。再次强调,如果你的证书不支持Certificate Transparency,此项需要设置为不可用。
如果需要调试一些由于采用了ATS而产生的问题,需要设置CFNETWORK_DIAGNOSTICS为1,这样就会打印出包含被访问的URL和ATS错误在内的NSURLSession错误信息。要确保处理了遇到的所有的错误消息,这样才能使ATS易于提高可靠性和扩展性。