相信很多小伙伴即将开始着手 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
错误信息。