的有效性,我们可以完全控制整个验证过程。但是要谨慎使用。
服务器信任策略管理者 (Server Trust Policy Manager)
ServerTrustPolicyManager
负责存储一个内部的服务器信任策略到特定主机的映射。这样Alamofire就可以评估每个主机不同服务器信任策略。
let serverTrustPolicies: [String: ServerTrustPolicy] = [ "test.example.com": .pinCertificates( certificates: ServerTrustPolicy.certificates(), validateCertificateChain: true, validateHost: true ), "insecure.expired-apis.com": .disableeva luation ] let sessionManager = SessionManager( serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies) )
注意:要确保有一个强引用引用着SessionManager
实例,否则当sessionManager
被销毁时,请求将会取消。
这些服务器信任策略将会形成下面的结果:
test.example.com
:始终使用证书链固定的证书和启用主机验证,因此需要以下条件才能是TLS握手成功:
- 证书链必须是有效的。
- 证书链必须包含一个已经固定的证书。
- Challenge主机必须匹配主机证书链的子证书。
insecure.expired-apis.com
:将从不评估证书链,并且总是允许TLS握手成功。
- 其他主机将会默认使用苹果提供的验证。
子类化服务器信任策略管理者
如果我们需要一个更灵活的服务器信任策略来匹配其他行为(例如通配符域名),可以子类化ServerTrustPolicyManager
,并且重写serverTrustPolicyForHost
方法。
class CustomServerTrustPolicyManager: ServerTrustPolicyManager { override func serverTrustPolicy(forHost host: String) -> ServerTrustPolicy? { var policy: ServerTrustPolicy?
验证主机
.performDefaulteva luation
、.pinCertificates
和.pinPublicKeys
这三个服务器信任策略都带有一个validateHost
参数。把这个值设为true
,服务器信任评估就会验证与challenge主机名字匹配的在证书里面的主机名字。如果他们不匹配,验证失败。如果设置为false
,仍然会评估整个证书链,但是不会验证子证书的主机名字。
注意:建议在实际开发中,把validateHost
设置为true
。
验证证书链
Pinning certificate 和 public keys 都可以通过validateCertificateChain
参数拥有验证证书链的选项。把它设置为true
,除了对Pinning certificate 和 public keys进行字节相等检查外,还将会验证整个证书链。如果是false
,将会跳过证书链验证,但还会进行字节相等检查。
还有很多情况会导致禁用证书链认证。最常用的方式就是自签名和过期的证书。在这些情况下,验证始终会失败。但是字节相等检查会保证我们从服务器接收到证书。
注意:建议在实际开发中,把validateCertificateChain
设置为true
。
应用传输安全 (App Transport Security)
从iOS9开始,就添加了App Transport Security (ATS),使用ServerTrustPolicyManager
和多个ServerTrustPolicy
对象可能没什么影响。如果我们不断看到CFNetwork SSLHandshake failed (-9806)
错误,我们可能遇到了这个问题。苹果的ATS系统重写了整个challenge系统,除非我们在plist文件中配置ATS设置来允许应用评估服务器信任。
<dict> <key>NSAppTransportSecurity</key> <dict> <key>NSExceptionDomains</key> <dict> <key>example.com</key> <dict> <key>NSExceptionAllowsInsecureHTTPLoads</key> <true/> <key>NSExceptionRequiresForwardSecrecy</key> <false/> <key>NSIncludesSubdomains</key> <true/>
是否需要把NSExceptionRequiresForwardSecrecy
设置为NO
取决于TLS连接是否使用一个允许的密码套件。在某些情况下,它需要设置为NO
。NSExceptionAllowsInsecureHTTPLoads
必须设置为YES
,然后SessionDelegate
才能接收到challenge回调。一旦challenge回调被调用,ServerTrustPolicyManager
将接管服务器信任评估。如果我们要连接到一个仅支持小于1.2
版本的TSL主机,那么还要指定NSTemporaryExceptionMinimumTLSVersion
。
注意:在实际开发中,建议始终使用有效的证书。
网络可达性 (Network Reachability)
NetworkReachabilityManager
监听WWAN
和WiFi
网络接口和主机地址的可达性变化。
let manager = NetworkReachabilityManager(host: "www.apple.com") manager?.listener = { status in print("Network Status Changed: \(status)") } manager?.startListening()
注意:要确保manager被强引用,否则会接收不到状态变化。另外