iOS 应用网络安全之 HTTPS
安全套接字层(Secure Socket Layer, SSL)是实现互联网安全通信的最普遍标准。Web 应用程序使用 HTTPS(基于 SSL 的 HTTP),HTTPS 使用数字证书来确保在服务器和客户端之间进行安全、加密的通信。在 SSL 连接中,客户机和服务器在发送数据之前都要对数据进行加密,然后由接受方对其进行解密。
1. HTTPS 握手流程
当浏览器(客户端)需要与某个安全站点建立连接时,先建立 TCP 连接(三次握手),然后再发生 SSL 会话握手:
- 请求:浏览器通过网络发送请求安全会话的消息(通常以 https 而非 http 开头的 URL)。
- 响应:服务器通过发送其证书(包括公钥)进行响应。
- 验证:浏览器检验服务器的证书是否有效,是否由其位于浏览器数据库中的可信 CA 签发,以及 CA 证书是否已过期。
- 密钥交换:如果证书有效,浏览器生成一个一次性的会话密钥,并使用服务器的公钥对该会话密钥进行加密后发送给服务器。
- 解密:服务器使用其专用密钥对消息进行解密,恢复会话密钥。
- 加密通信:握手之后,客户端已验证 Web 站点的身份,双方拥有会话密钥副本,后续所有通信均使用该密钥加密。
上述是普遍的单向验证方式(客户端验证服务端)。也可以做双向验证(服务端也验证客户端),一般用于银行业务(如 U 盾)。本文主要关注普遍的单向验证方式的应用。
2. iOS 移动开发 HTTPS 应用现状
当下绝大多数的移动互联网项目都采用 HTTP、HTTPS 协议作为前后端的数据接口协议。在 iOS 开发群体中,绝大部分都在项目中应用了第三方开源的 HTTP 请求框架 AFNetworking 来快速高效地开发。
从 iOS 9.0 开始,Apple 默认只允许采用经过权威证书颁发机构签名的证书的 HTTPS 站点的访问。一切是为了安全。开发者需要在 Info.plist 中设置 App Transport Security 才能加载非 HTTP 的资源,或者配置例外域名。
HTTPS 的服务器配置的证书分两大类:
- 权威机构签名颁发的证书:通常需要购买服务,也有少数机构提供免费证书(如 Let's Encrypt, WoSign)。
- 自签名证书:服务器配置的是研发人员自己签名生成的证书,常用于内部测试环境。
3. AFN 调用使用权威机构颁发证书的 HTTPS 接口
AFNetworking 框架修复了 SSL 中间人攻击漏洞,并强烈要求开发者使用公钥绑定或者证书绑定的安全策略。正确使用 AFNetworking 请求这类证书的 HTTPS 站点代码如下:
AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey];
policy.validatesDomainName = YES;
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.securityPolicy = policy;
manager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
对于这类证书的站点,Info.plist 都不需要特殊设置,因为已经是权威机构颁发的证书了。我们只需要设置验证绑定方式和验证域名以防止中间人攻击。
4. AFN 调用使用我们自己签名证书的 HTTPS 接口
对于使用自签名证书的站点,浏览器打开 web 站点也会默认阻止访问,除非用户手动把该站点加入信任列表。这个手动加入的过程其实就是不去验证服务器的合法性,任性地认为服务器是可信赖的。
如果在 App 端不严格验证,虽然可以成功访问目标服务器返回数据,但中间很有可能返回的数据不是真正的目标服务器返回的数据,也可能是网络传输中间的第三者伪装返回的数据。传输的数据被人窃取甚至篡改都是很可能的。
4.1 不正确的做法
浏览器手动加入自签名站点到信任列表的操作,相当于 iOS 开发中 AFNetworking 的 API 如下设置:
- Info.plist 设置:
NSAppTransportSecurity NSAllowsArbitraryLoads


