AFNetworking里面的HTTPS安全策略实现原理

在使用AFNetworking来作为网络请求库时,对于HTTPS请求的证书验证,我们需要去初始化继承于AFURLSessionManager的AFHTTPSessionManager,设置好securityPolicy, AFURLSessionManager里面有3种安全策略可供使用者选择:

@interface AFURLSessionManager : NSObject <NSURLSessionDelegate,...>
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
...
@end

@interface AFSecurityPolicy : NSObject <NSSecureCoding, NSCopying>
@property (readonly, nonatomic, assign) AFSSLPinningMode SSLPinningMode;
...
@end

typedef NS_ENUM(NSUInteger, AFSSLPinningMode) {
    AFSSLPinningModeNone,  // 不使用本地证书验证服务器
    AFSSLPinningModePublicKey,  // 使用本地证书里面的公钥验证服务器
    AFSSLPinningModeCertificate,  // 使用本地证书验证服务器
};

iOS 客户端在发送网络请求时,如果收到服务器的质询(NSURLAuthenticationChallenge)时会调用NSURLSessionDelegate里面的代理方法, AFNetworking安全策略的实现就是在这个方法里面让初始化时设置的securityPolicy去完成的。(NSURLSessionTaskDelegate里面的那个方法原理一样所以这里不讲)

- (void)URLSession:(NSURLSession *)session
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
    NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
    __block NSURLCredential *credential = nil;

    if (self.sessionDidReceiveAuthenticationChallenge) {
        disposition = self.sessionDidReceiveAuthenticationChallenge(session, challenge, &credential);
    } else {
        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
                credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
                if (credential) {
                    disposition = NSURLSessionAuthChallengeUseCredential;
                } else {
                    disposition = NSURLSessionAuthChallengePerformDefaultHandling;
                }
            } else {
                disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
            }
        } else {
            disposition = NSURLSessionAuthChallengePerformDefaultHandling;
        }
    }

    if (completionHandler) {
        completionHandler(disposition, credential);
    }
}

通过源码分析可知其实现原理:
第一步:在初始化AFHTTPSessionManager时就初始化securityPolicy对象,设置好需要的属性。
第二步:在需要验证时调用securityPolicy对象方法- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain
第三步:具体的验证方式,分三种情况进行:

情况一: AFSSLPinningModeNone,  
// APP内部没放证书,要验证服务器证书
返回验证结果是:
return self.allowInvalidCertificates || AFServerTrustIsValid(serverTrust);
// 即(允许服务器无效证书) || (不允许无效证书但证书验证通过)为YES ,否则为NO;


情况二:AFSSLPinningModeCertificate,   
// APP内部放了证书,要验证服务器证书,且证书要跟APP内部的证书比对
第一步:将本地的证书设置为服务器信任`serverTrust`的锚点证书。
 SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates);
第二步:对设置了锚点证书的`serverTrust`进行服务器证书验证
BOOL IsValid = AFServerTrustIsValid(serverTrust);
第三步:上一步验证通过后,将服务器证书从`serverTrust`获取出来,并与本地证书作比对,比对结果作为返回值。
NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust);
for (NSData *trustChainCertificate in [serverCertificates reverseObjectEnumerator]) {
         if ([self.pinnedCertificates containsObject:trustChainCertificate]) {
                    return YES;
           }
  }

情况三:AFSSLPinningModeCertificate,  
 // APP内部放了证书,要验证服务器证书,且要将服务器证书里面的公钥跟APP内部证书的公钥比对
第一步: 在服务器证书验证通过后,将服务器证书的公钥从`serverTrust`中取出
NSArray *publicKeys = AFPublicKeyTrustChainForServerTrust(serverTrust);
第二步:本地证书的公钥是在初始化的时候就提取出来了,所以这里直接将本地证书中公钥与publicKeys比对,将结果作为返回值.
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。