美文网首页
AFNetworking框架下的SSL服务器证书的自定义验证

AFNetworking框架下的SSL服务器证书的自定义验证

作者: Mr狮子先生 | 来源:发表于2017-12-29 11:19 被阅读0次

AFNetworking框架下的SSL服务器证书的自定义验证

如何使用本地证书进行SSL验证

开启SSL验证

需要设置 AFHTTPSessionManagersetSecurityPolicy ,使用 AFSSLPinningModeCertificate 证书验证模式

[AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]

然后进行 AFSecurityPolicy 的一系列设置,如下

+ (AFSecurityPolicy *)customSecurityPolicy {
    AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]; // 设置证书验证模式
    [securityPolicy setAllowInvalidCertificates:NO]; //  是否允许无效证书(也就是自建的证书),默认为NO.如果是需要验证自建证书,需要设置为YES
    [securityPolicy setValidatesDomainName:YES]; // 验证域名
    
    // 设置证书
    NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"itouchtv_app" ofType:@"cer"];
    NSData *certData = [NSData dataWithContentsOfFile:cerPath];
    [securityPolicy setPinnedCertificates:[NSSet setWithObject:certData]];
    
    return securityPolicy;
}

关闭SSL验证

只需要使用 AFSSLPinningModeNone 模式,即可关闭SSL验证

[AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone]

自定义实现SSL证书的验证逻辑

使用 NSURLSession 走 HTTPS 通道访问网站或接口

NSURLSession的 -URLSession:didReceiveChallenge:completionHandler: 回调中会收到一个类型为 NSURLAuthenticationChallenge 的质询 challenge,在此回调中,进行证书信息的认证,以决定是否继续连接服务器,或者断开连接。

通过 challenge.protectionSpace.authenticationMethod 获取保护空间要求认证的方式,如果值是 NSURLAuthenticationMethodServerTrust ,就可以走数字证书的自定义验证逻辑了。

AFNetworking 下的具体实现方式

NSURLSession 是相同的原理,质询的回调是 AFHTTPSessionManagersetSessionDidReceiveAuthenticationChallengeBlock

SSL证书的层级和自定义验证逻辑

SSL证书,一般有三层,根证书和二级证书是申请证书时的权威可信的颁发机构的证书,在换证书时,是保持不变的,所以可以使用字符串常量来直接验证是否相等,即可完成根证书和二级证书的验证。

而最后一层,才是每个证书申请者自己的独特的信息,也是需要自定义验证的部分。

具体代码

关键在于 isServerTrust 变量,表示自定义验证通过。

        // 设置验证模式
        AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
        securityPolicy.allowInvalidCertificates = NO;//是否允许使用自签名证书
        securityPolicy.validatesDomainName = YES;//是否需要验证域名,默认YES
        [manager setSecurityPolicy:securityPolicy];

        // 自定义验证证书
        [manager setSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential *__autoreleasing *_credential)
        {
            BOOL isServerTrust = NO;//所有证书验证通过
            
            BOOL isCertRootTrust = NO;//根证书验证通过
            BOOL isCertSecondTrust = NO;//二级证书验证通过
            BOOL isCertClientTrust = NO;//最后一级,本地证书验证通过
            
            //取得服务器返回的三级证书
            SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust];
            
            //遍历服务器返回的证书
            CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust);
            for (CFIndex i = certificateCount - 1; i >= 0; i--) {
                SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i);
                NSString *subjectSummary = (__bridge_transfer NSString *)SecCertificateCopySubjectSummary(certificate);
                
                //证书NSData转为NSString
                CFDataRef certData = SecCertificateCopyData(certificate);
                NSString *certificateBase64String = [(__bridge_transfer NSData *)certData base64EncodedStringWithOptions:0];
                
                //比较本地保存的一级和二级证书NSString
                if (i == certificateCount - 1) {//一级根证书
                    if ([certificateBase64String isEqualToString:certStringForRoot]) {
                        isCertRootTrust = YES;
                    }
                } else if (i == certificateCount - 2) {//第二级证书
                    if ([certificateBase64String isEqualToString:certStringForSecondLevel]) {
                        isCertSecondTrust = YES;
                    }
                } else if (i == 0) {//第三级:要部分验证的本地证书
  
                    //获取本地证书
                    NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"app" ofType:@"cer"];
                    NSData *certData = [NSData dataWithContentsOfFile:cerPath];
                    SecCertificateRef certificateLocal = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certData);
                    
                    //域名
                    NSString *subjectSummaryLocal = (__bridge_transfer NSString *)SecCertificateCopySubjectSummary(certificateLocal);
                    
                    //验证
                    if ([subjectSummary isEqualToString:subjectSummaryLocal])
                    {
                        isCertClientTrust = YES;
                    }
                }
            }
            
            NSLog(@"一级根证书是否验证通过:%@,第二级证书是否验证通过:%@,第三级本地证书是否验证通过:%@", @(isCertRootTrust), @(isCertSecondTrust), @(isCertClientTrust));
            
            //判断所有证书是否验证通过
            if (isCertRootTrust && isCertSecondTrust && isCertClientTrust) {
                isServerTrust = YES;
            }

            NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
            __autoreleasing NSURLCredential *credential = nil;
            if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
//                if ([manager.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) { // 此处注释的,为默认的处理方式
                if (isServerTrust) { // 要自定义验证,需要使用自己的判断逻辑
                    credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
                    if (credential) {
                        disposition = NSURLSessionAuthChallengeUseCredential;
                    } else {
                        disposition = NSURLSessionAuthChallengePerformDefaultHandling;
                    }
                } else {
                    disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
                }
            } else {
                disposition = NSURLSessionAuthChallengePerformDefaultHandling;
            }
            return disposition;
        }];
        
        [TTVPlayerMoniter sharedMointerManager];

    });
    

相关文章

网友评论

      本文标题:AFNetworking框架下的SSL服务器证书的自定义验证

      本文链接:https://www.haomeiwen.com/subject/kerigxtx.html