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

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

 

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

 

#### 开启SSL验证app

须要设置 `AFHTTPSessionManager` 的 `setSecurityPolicy` ,使用 `AFSSLPinningModeCertificate` 证书验证模式框架

 

```网站

[AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]lua

```code

 

而后进行 `AFSecurityPolicy` 的一系列设置,以下orm

```server

+ (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` 是相同的原理,质询的回调是 `AFHTTPSessionManager` 的 `setSessionDidReceiveAuthenticationChallengeBlock` 。

 

 

#### 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];

 

    });

    

```

相关文章
相关标签/搜索