四、Security部分
顾名思义这块是AFNetworking中的安全框架,在iOS9之后网络请求中加入SSL使用HTTPS几乎已经成为苹果的强制要求了。Security这部分主要功能就是用来验证HTTPS的证书是否有效。这部分主要是通过AFSecurityPolicy这个类来实现的。
下面还是通过一个具体的调用来分析,就从AFNetworking的默认调用开始,之前在分析NSURLSession部分时提到过,在AFURLSessionManager的初始化方法中设置:
首先分析一下AFSecurityPolicy的这个初始化方法:
可看出在这一系列的初始化方法中主要设置了这两个属性,securityPolicy.SSLPinningMode = AFSSLPinningModeNone和self.validatesDomainName = YES。
表示是否验证域名,默认是YES。
AFSSLPinningModeNone表示不使用固定证书(本地)验证服务器。直接从客户端系统中的受信任颁发机构 CA 列表中去验证。
AFSSLPinningModePublicKey代表会对服务器返回的证书中的PublicKey进行验证,通过则通过,否则不通过。
AFSSLPinningModeCertificate代表会对服务器返回的证书同本地证书全部进行校验,通过则通过,否则不通过。
可看出AFNetworking默认使用的是AFSSLPinningModeNone模式。
继续查看发现AFURLSessionManager会在这两个地方使用这个属性:
这两个方法分别是实现了NSURLSessionDelegate和NSURLSessionTaskDelegate的协议方法。然后通过这方法里实现https的认证。服务端发起的一个验证挑战,客户端需要根据挑战的类型提供相应的挑战凭证。当然,挑战凭证不一定都是进行HTTPS证书的信任,也可能是需要客户端提供用户密码或者提供双向验证时的客户端证书。当这个挑战凭证被验证通过时,请求便可以继续顺利进行。下面具体分析认证过程:
NSURLAuthenticationChallenge*类型的challenge 表示一个认证的挑战,提供了关于这次认证的全部信息。接着看:
challenge的protectionSpace属性保存了需要认证的保护空间,NSURLProtectionSpace *类型的protectionSpace主机地址,端口和认证方法等重要信息。由上边代码可知如果protectionSpace.authenticationMethod是NSURLAuthenticationMethodServerTrust,就对保护空间中的 serverTrust 以及域名host进行认证,并根据认证的结果,会在 completionHandler 中传入不同的disposition 和credential参数。
继续深入分析AFSecurityPolicy的认证方法:
第一个条件分支
如果有服务器域名、设置了允许信任无效或者过期证书(自签名证书)、需要验证域名、没有提供证书或者不验证证书,返回NO。
这一步为设置验证策略,如果要验证域名,就以域名为参数创建一个策略,否则创建默认的basicX509策略。
这一步是验证证书的有效性,如果是AFSSLPinningModeNone,不做本地证书验证,从客户端系统中的受信任颁发机构 CA 列表中去验证服务端返回的证书。但是如果不做本地证书验证,从客户端系统中的受信任颁发机构 CA 列表中去验证服务端返回的证书通不过的话,而且allowInvalidCertificates不允许自签,返回NO。
调用下面这个方法进行验证有效性:
可看到这个方法里边都是对系统库<Security/Security.h>中方法的调用。
接下来是通过不同的self.SSLPinningMode进行对服务器信任的验证。
如果是AFSSLPinningModeNone直接返回NO。
如果是AFSSLPinningModeCertificate:
首先把证书data用系统方法SecCertificateCreateWithData转成 SecCertificateRef 类型的数据,再调用系统方法SecTrustSetAnchorCertificates将pinnedCertificates设置成需要参与验证的Anchor Certificate(锚点证书)。
参与校验锚点证书之后,假如验证的数字证书是这个锚点证书的子节点,即验证的数字证书是由锚点证书对应CA或子CA签发的,或是该证书本身,则信任该证书),具体就是调用SecTrustEvaluate来验证(如上)。
接下来这块:
从我们需要被验证的服务端证书,去拿证书链,如果我们的证书中,有一个和它证书链中的证书匹配的,就返回YES。否则没有匹配。(注意看:在匹配时调用了[serverCertificates reverseObjectEnumerator]这个方法得到一个前边获取的数组反转后的数组,反转前是从叶子节点到根节点,反转后是从根节点到叶子节点。)
这个函数是通过调用系统的相关方法来获取证书链。
如果是AFSSLPinningModePublicKey:
先调用AFPublicKeyTrustChainForServerTrust方法从serverTrust中取出服务器端传过来的所有可用的证书,并依次得到相应的公钥。再通过双重遍历并调用方法AFSecKeyIsEqualToKey对比本地的证书公钥和服务器传过来的证书公钥,如果相同的对数大于0,则说明验证通过。
就此整个使用过程分析结束。和上篇的AFNetworkReachabilityManager类似,AFSecurityPolicy是对系统C语言安全库<Security>的一个OC封装,提供了简便易用的OC接口。
网友评论