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

 

    });

    

```

相關文章
相關標籤/搜索