相信很多小伙伴即将开始着手 iOS 9 的适配工作了,下面我们就来了解一下 iOS 9 的一项新特性: ATS。
什么是 ATS
ATS 的全称是 App Transport Security,是iOS9的一个新特性,它的主要作用在于增强数据访问安全性。 App Transport Security Technote
在基于 iOS 9 的 SDK 编译的 APP 中,默认情况下任何使用 NSURLConnection、CFURL 以及 NSURLSession 的 HTTP请求,都会统一使用 TLS 1.2 协议。
什么是 SSL/TLS
SSL (Secure Sockets Layer ,安全套接层),及其继任者 TLS (Transport Layer Security ,传输层安全) 是为网络通信提供安全及数据完整性的一种安全协议。TLS 与 SSL 在传输层对网络连接进行加密。
什么是 HTTP/HTTPS
HTTP 的全称为 HyperText Transfer Protocol,而 HTTPS 的全称为 Hyper Text Transfer Protocol over Secure Socket Layer,也即 HTTP over SSL。那么也就是说,HTTP 采用 SSL/TLS 协议就是从 HTTP 提升到 HTTPS 的过程,也就是 ATS。
为什么要使用 ATS
从前面的介绍不难看出,不使用 SSL/TLS 的 HTTP 通信是不加密的,这带来的风险是显而易见的,任何第三方都可以对你的通信进行窃听(eavesdropping)、篡改(tampering) 甚至冒充(pretending)。 SSL\TLS 的存在,恰恰是为了解决这三种风险,它对所有信息进行加密,且具备可靠有效的校验机制及身份证书。
我是否受到影响、我可以不使用 ATS 吗
如果你的网络请求使用的是第三方库 AFNetworking,由于其 AFHTTPRequestOperationManager 中的实现采用了我们前面提到的 NSURLConnection,因此在 AFNetworking 更新之前,如果你的 APP 是基于 iOS 9 的 SDK 编译,你和服务器的小伙伴可能要面临加班了。
苹果在其官方文档中指出 NSURLConnection 在 iOS 9 中已被废弃并建议使用 NSURLSession:
The NSURLConnection API in the Foundation framework. Use NSURLSession APIs instead.
因此,我们刚才提到的第三方类库 AFNetworking 对此也有一个更新计划: AFNetworking 更新计划
你可以在项目的 Target 中进入 Build Setting 找到 Architectures 下的 Base SDK 对所使用的 SDK 进行确认。
当然,虽然苹果并不建议,某些情况下你仍旧还是可以选择不启用 ATS (例如你使用了是你不具备控制权限且不支持 HTTPS 的 CDN),在官方文档和 WWDC Session (@00:30:18) 也给出了解决方案:
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 Info.plist file.
也就是说:
如果你希望完全禁用 ATS,具体的方法是通过将 Info.plist 中的 NSAppTransportSecurity 中的 NSAllowsArbitraryLoads 改为 YES。
如果你只希望部分 URL 不使用 ATS,那么你需要在 Info.plist 中配置 NSExceptionDomains 来针对性的关闭 ATS 或是 ATS 的部分选项。在该字典中你可以使用的有:
-
NSIncludesSubdomains -
NSExceptionAllowInsecureHTTPLoads -
NS_ThirdParty_ExceptionAllowsInsecureHTTPLoads
-
NSExceptionRequiresForwardSecrecy -
NS_ThirdParty_ExceptionRequiresForwardSecrecy
-
NSExceptionMinimumTLSVersion -
NS_ThirdParty_ExceptionMinimumTLSVersion
其中带有 ThirdParty 关键字的条目与其去掉 ThirdParty 关键字后的同名条目功能相同。
其他第三方库例如 ASIHTTPRequest(已停止更新)、CFSocket 并没有受到影响。
另外,要注意,即使服务器已支持 SSL/TLS 1.2,但 ATS 要求站点使用支持 Forward Secrecy 协议的密码以及符合 ATS 规格 的证书。
官方文档 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
如何使用 ATS
| 类型 | 说明 |
|---|---|
| HTTPS Only | 只有 HTTPS,在所有情况下一律使用 ATS |
| Mix & Match | 混合模式,仅针对部分通信禁用 ATS |
| Opt Out | 禁用 ATS,在任何情况下都不使用 ATS |
| Opt Out With Exceptions | 禁用 ATS 但允许例外,仅针对部分通信启用 ATS |
下面分别做一下介绍:
HTTPS Only
如果你的 APP 没有 HTTPS 以外的通信,那么不需要做任何改变,也不需要禁用 ATS。
如果你连接的服务器已经支持 SSL\TLS 1.2 仍旧无法在 iOS 9 中进行网络通信,你可能需要参照本文前面提到的 Forward Secrecy 部分。(点击跳转)
Mix & Match
毫无疑问,你的应用与一个不符合 ATS 要求的服务器通信是很有可能的:
- 服务器不支持
HTTPS - 服务器支持
HTTPS但没有使用SSL\TLS 1.2 - 服务器没有使用支持
Forward Secrecy协议的密码
对于它们,我们需要在 Info.plist 中进行配置:
- 服务器不支持
HTTPS
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>yourdomain.com</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<false/>
</dict>
</dict>
</dict>
这里我们通过定义例外情况(Exception),允许了在与该子域交互的时(仅针对该子域)暂时关闭 ATS。需要注意的是 NSExceptionAllowsInsecureHTTPLoads 关键字并不仅仅只是与使用 HTTPS 相关。
- 服务器支持
HTTPS但没有使用SSL\TLS 1.2
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>yourdomain.com</key>
<dict>
<key>NSThirdPartyExceptionMinimumTLSVersion</key>
<string>TLSv1.1</string>
</dict>
</dict>
</dict>
这里我们同样定义了例外情况(Exception),指明应该使用的最低 TLS 的版本。
- 服务器没有使用支持
Forward Secrecy协议的密码
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>yourdomain.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>
其中:
通过将 NSIncludesSubdomains 设置为 YES 来指明例外情况(Exception)适用于特定域名的所有子域。
通过将 NSExceptionRequiresForwardSecrecy 设置为 NO
扩展可接受的密码列表,来指明特定域名可以使用不支持 Forward Secrecy 协议的密码。
Opt Out
如果你需要完全禁用 ATS,或者你想偷懒,那么就像我们前面介绍的那样,你可以通过修改 Info.plist 文件来达到目的:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Opt Out With Exceptions
最后一种情况是,你希望单独针对某些例外情况(Exception)开启 ATS,我们同样通过修改 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>
关于 Certificate Transparency
ATS 的大部分安全特性都是默认可用的,但如果你的证书支持 Certificate Transparency,你仍旧需要设置 NSRequiresCertificateTransparency 为可用。反之如果你的证书不支持 Certificate Transparency,请设置为不可用。
关于调试与错误信息输出
如果你需要调试一些因 ATS 产生的问题,你可能需要将 CFNETWORK_DIAGNOSTICS 设置为 1,以便输出包含被访问 URL 以及 ATS 错误的 NSURLSession 错误信息。