相信很多小伙伴即将开始着手 iOS 9 的适配工作了,下面我们就来了解一下 iOS 9 的一项新特性: ATS

什么是 ATS

ATS 的全称是 App Transport Security,是iOS9的一个新特性,它的主要作用在于增强数据访问安全性。 App Transport Security Technote

在基于 iOS 9 的 SDK 编译的 APP 中,默认情况下任何使用 NSURLConnectionCFURL 以及 NSURLSessionHTTP请求,都会统一使用 TLS 1.2 协议。

什么是 SSL/TLS

SSL (Secure Sockets Layer ,安全套接层),及其继任者 TLS (Transport Layer Security ,传输层安全) 是为网络通信提供安全及数据完整性的一种安全协议。TLSSSL 在传输层对网络连接进行加密。

什么是 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/TLSHTTP 通信是不加密的,这带来的风险是显而易见的,任何第三方都可以对你的通信进行窃听(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 (例如你使用了是你不具备控制权限且不支持 HTTPSCDN),在官方文档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 错误信息。