iOS下訪問HTTPS的方法

本文主要講AFNetworking對https的處理方式,以及iOS下訪問https的方法滨砍。

HTTP與HTTPS

HTTP是超文本傳輸協(xié)議蕴潦,它是互聯(lián)網數(shù)據(jù)通信的基礎呼畸。

HTTPS是超文本傳輸安全協(xié)議莱睁,簡單講是HTTP的安全版待讳。

HTTPS經由HTTP進行通信,但利用SSL/TLS來加密數(shù)據(jù)包仰剿,HTTP默認端口是80,HTTPS是443痴晦。

HTTPS在HTTP請求的基礎上多加了一個證書認證的流程南吮,認證通過之后,數(shù)據(jù)開始加密傳輸誊酌。這個認證過程叫做SSL握手部凑。

具體的握手過程可以參考:
《SSL握手過程》
《SSL/TLS握手過程詳解》

SSL握手大致過程:

①客戶端向服務器傳送客戶端 SSL 協(xié)議版本號露乏、它所支持的加密算法列表、隨機數(shù)等信息涂邀。
②服務器從加密列表中選擇一種加密算法瘟仿,并和它的證書、第二個隨機數(shù)一起發(fā)給客戶端比勉。
③客戶端驗證證書是否有效劳较,如果驗證沒有通過,通訊將斷開浩聋;如果驗證通過观蜗,將繼續(xù)進行。
④客戶端產生第二個隨機數(shù)衣洁,并用服務器的證書中的公鑰對其加密后傳給服務器墓捻,服務器使用私鑰解密得到第三個隨機數(shù)。
⑤客戶端與服務器根據(jù)三個隨機數(shù)生成對稱加密的密鑰坊夫。
⑥SSL的握手部分結束砖第,SSL安全通道的數(shù)據(jù)通訊開始。
⑦客戶端與服務器之后的通訊信息加密后傳輸环凿,由于數(shù)據(jù)是加密過的厂画,所以就算請求被截取也是安全的。

進行 https 請求時拷邢,我們只需要負責第③步的證書驗證袱院,其它的都交給系統(tǒng)去做。系統(tǒng)會回調代理方法讓我們去進行證書驗證瞭稼。

下面先分析一下AFNetworking的驗證方法忽洛。

AFNetworking對HTTPS的處理

AFNetworking在AFURLSessionManager類中實現(xiàn)了系統(tǒng)的代理方法
-URLSession:task:didReceiveChallenge:completionHandler:
-URLSession:didReceiveChallenge:completionHandler:,兩個方法中的處理代碼是相同的环肘。

- (void)URLSession:(NSURLSession *)session
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{
    // 默認使用默認方式處理證書欲虚,這種方式無法驗證通過自簽名證書
    NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
    __block NSURLCredential *credential = nil;

    // 如果主動通過-setTaskDidReceiveAuthenticationChallengeBlock:方法設置處理方法,則按照block設置的方法處理
    // 如果沒有就走AF的處理方式(else分支)
    if (self.taskDidReceiveAuthenticationChallenge) {
        disposition = self.taskDidReceiveAuthenticationChallenge(session, task, challenge, &credential);
    } else {
        // 如果驗證方法為NSURLAuthenticationMethodServerTrust悔雹,說明服務器端需要客戶端返回一個根據(jù)認證挑戰(zhàn)的保護空間提供的信任(即challenge.protectionSpace.serverTrust)產生的挑憑據(jù)复哆,用+credentialForTrust方法創(chuàng)建
        // 如果驗證方法不是NSURLAuthenticationMethodServerTrust砸捏,則challenge.protectionSpace.serverTrust為nil
        // 一般情況下纫普,服務器的驗證方式都是ServerTrust赴魁,如果不是巴元,就用其它方法創(chuàng)建憑據(jù)(參考那個官方文檔鏈接)
        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            // 使用設置好的安全策略securityPolicy進行驗證
            // serverTrust:用于執(zhí)行X.509證書信任評估级解。其實就是一個容器软瞎,裝了服務器端需要驗證的證書的基本信息撵孤、公鑰等等肆氓,不僅如此,它還可以裝一些評估策略久免,還有客戶端的錨點證書浅辙,這個客戶端的證書,可以用來和服務端的證書去匹配驗證的阎姥。
            // domain:服務器域名
            if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
                // 如果驗證通過记舆,則通過challenge.protectionSpace.serverTrust創(chuàng)建一個新憑據(jù),供NSURLSession判斷
                disposition = NSURLSessionAuthChallengeUseCredential;
                credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
            } else {
                // 如果驗證不通過呼巴,則取消此次網絡請求
                disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
            }
        } else {
            // 如果驗證方法不是ServerTrust泽腮,則使用默認的方式處理
            disposition = NSURLSessionAuthChallengePerformDefaultHandling;
        }
    }

    // 回調block
    if (completionHandler) {
        completionHandler(disposition, credential);
    }
}

大體邏輯是:

  • 如果設置了taskDidReceiveAuthenticationChallenge這個block,就直接回調這個block進行驗證伊磺;
  • 否則就進入else分支盛正,else分支中,驗證方法如果是NSURLAuthenticationMethodServerTrust屑埋,就使用AFSecurityPolicy類的-evaluateServerTrust:forDomain:方法進行驗證豪筝;
  • 如果是別的驗證方法,就使用默認方式處理摘能;
  • -evaluateServerTrust:forDomain:方法中如果驗證通過就創(chuàng)建一個憑據(jù)對象续崖,使用completionHanlder這個block傳遞給NSURLSession內部,讓它進行之后的工作团搞,沒有驗證通過就直接取消此次網絡請求严望。

其中 X.509 是一種廣泛使用的數(shù)字證書標準,它規(guī)范了公開密鑰認證逻恐、證書吊銷列表像吻、授權證書、證書路徑驗證算法等复隆。

該方法有兩個重要的參數(shù):challengecompletionHandler拨匆。

challenge是進行https請求進行時,服務端發(fā)送過來的質詢挽拂,它包含了驗證請求的所有信息惭每,當接收到質詢之后客戶端就要開始進行驗證。

challenge中最重要的屬性是protectionSpace亏栈,它是需要身份驗證的空間保護的說明台腥,包含了請求的主機、端口號绒北、代理類型黎侈、使用協(xié)議、服務端要求客戶端對其驗證的方法和服務器的SSL傳輸狀態(tài)等重要信息镇饮。服務端指定的驗證方法的類型有以下幾種:

NSURLAuthenticationMethodDefault
NSURLAuthenticationMethodHTTPBasic
NSURLAuthenticationMethodHTTPDigest
NSURLAuthenticationMethodHTMLForm
NSURLAuthenticationMethodNTLM
NSURLAuthenticationMethodNegotiate
NSURLAuthenticationMethodClientCertificate
NSURLAuthenticationMethodServerTrust

其中HTTP Basic蜓竹、HTTP Digest與NTLM認證都是基于用戶名/密碼的認證箕母,ClientCertificate認證要求從客戶端上傳證書储藐。

一般在HTTPS訪問的過程中俱济,服務端要求的認證方法一般都是ServerTrust方式。

如果是HTTP Basic方式钙勃,客戶端需要將用戶名和密碼信息放到憑據(jù)中蛛碌,然后傳遞給服務端。

如果是ClientCertificate辖源,表示雙向認證蔚携,處理的方式是使用
-credentialWithIdentity:certificates:persistence: 來獲取本地證書創(chuàng)建憑證,使用該憑證來進行連接克饶。

更多認證方法的處理酝蜒,可以參考蘋果官方文檔

對于completionHandler矾湃,在創(chuàng)建好包含驗證信息的憑據(jù)之后必須調用亡脑,這樣才會將驗證信息發(fā)送給服務端。它的第一個參數(shù)的一個枚舉邀跃,代表如何處理這個證書:

typedef NS_ENUM(NSInteger, NSURLSessionAuthChallengeDisposition) {
    NSURLSessionAuthChallengeUseCredential = 0,   // 使用服務器發(fā)回的憑據(jù),可能為空
    NSURLSessionAuthChallengePerformDefaultHandling = 1,  // 默認的處理方法霉咨,如果未執(zhí)行此代理,則忽略憑據(jù)參數(shù)
    NSURLSessionAuthChallengeCancelAuthenticationChallenge = 2,  //取消整個請求拍屑,忽略憑據(jù)參數(shù)
    NSURLSessionAuthChallengeRejectProtectionSpace = 3, // 這次質詢被拒絕途戒,嘗試下一個身份驗證保護控件 ,忽略憑據(jù)參數(shù)
} ;

第二個參數(shù)表示憑據(jù),創(chuàng)建好憑據(jù)后調用completionHandler僵驰,就能把驗證信息發(fā)送給服務端喷斋,服務器證書的驗證就完成了。

AFSecurityPolicy類中的判斷方法-evaluateServerTrust:forDomain:如下:

- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
              forDomain:(NSString *)domain
{
    // domain                   域名(上步傳來的challenge.protectionSpace.host)
    // allowInvalidCertificates 允許無效證書(自簽名證書)蒜茴,默認為NO
    // validatesDomainName      驗證域名星爪,默認為YES
    // SSLPinningMode           評估模式,默認為None
    // pinnedCertificates       存放證書的集合
    // 有域名矮男,允許自簽名證書移必,需要驗證域名,由于要驗證域名毡鉴,所以SSLPinningMode不能為None崔泵,證書也不能為0個
    if (domain && self.allowInvalidCertificates && self.validatesDomainName && (self.SSLPinningMode == AFSSLPinningModeNone || [self.pinnedCertificates count] == 0)) {
        NSLog(@"In order to validate a domain name for self signed certificates, you MUST use pinning.");
        return NO;
    }

    // policies用來存放驗證策略,如果需要驗證域名猪瞬,則根據(jù)域名生成一個證書鏈驗證策略對象憎瘸,否則返回一個默認的X.509標準策略對象
    NSMutableArray *policies = [NSMutableArray array];
    if (self.validatesDomainName) {
        [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)];
    } else {
        [policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()];
    }

    // 給serverTrust設置策略驗證,即告訴客戶端如何驗證serverTrust
    SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);

    if (self.SSLPinningMode == AFSSLPinningModeNone) {
        // 當SSLPinningMode為AFSSLPinningModeNone時陈瘦,如果是自簽名證書則直接返回成功幌甘,如果不是,就評估serverTrust的證書
        // 允許無效(自簽名)證書就返回YES,否則就判斷serverTrust是否有效
        // AFServerTrustIsValid函數(shù)會調用系統(tǒng)評估證書函數(shù)锅风,去系統(tǒng)根證書里去找是否有匹配的證書酥诽。
        return self.allowInvalidCertificates || AFServerTrustIsValid(serverTrust);
    } else if (!AFServerTrustIsValid(serverTrust) && !self.allowInvalidCertificates) {
        // 當SSLPinningMode不是AFSSLPinningModeNone時,如果既沒有驗證成功又不允許無效證書皱埠,則直接返回評測失敗肮帐。
        return NO;
    }

    switch (self.SSLPinningMode) {
        // 前面已經處理了AFSSLPinningModeNone,所以這里直接返回NO
        case AFSSLPinningModeNone:
        default:
            return NO;
        case AFSSLPinningModeCertificate: {
            NSMutableArray *pinnedCertificates = [NSMutableArray array];
            for (NSData *certificateData in self.pinnedCertificates) {
                // 把證書data轉成SecCertificateRef類型的數(shù)據(jù)(DER編碼的X.509證書)
                [pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)];
            }
            // 將pinnedCertificates設置成錨點證書(Anchor Certificate边器,設置之后训枢,假如驗證的數(shù)字證書是這個錨點證書的子節(jié)點,即驗證的數(shù)字證書是由錨點證書對應CA或子CA簽發(fā)的忘巧,或是該證書本身恒界,則信任該證書),具體就是調用SecTrustEvaluate來驗證砚嘴。
            // serverTrust是服務器來的驗證十酣,包含需要被驗證的證書。
            SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates);

            // 正常情況下自簽在之前是驗證通過不了的枣宫,如果把我們的自簽名證書加入self.pinnedCertificates婆誓,在這里就能驗證成功了。
            // 再去調用之前的serverTrust去驗證該證書是否有效
            if (!AFServerTrustIsValid(serverTrust)) {
                return NO;
            }

            // 這個方法和我們之前的錨點證書已經沒關系了也颤,而是從被驗證的服務端證書拿證書鏈
            // 去被驗證的服務端證書取證書鏈
            NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust);
        
            for (NSData *trustChainCertificate in [serverCertificates reverseObjectEnumerator]) {
                // 如果我們的證書中洋幻,有一個和證書鏈中的證書匹配就返回YES
                if ([self.pinnedCertificates containsObject:trustChainCertificate]) {
                    return YES;
                }
            }
        
            return NO;
        }
        case AFSSLPinningModePublicKey: {
            // 公鑰驗證 AFSSLPinningModePublicKey模式同樣是用證書綁定(SSL Pinning)方式驗證,客戶端要有服務端的證書拷貝翅娶,只是驗證時只驗證證書里的公鑰文留,不驗證證書的有效期等信息。只要公鑰是正確的竭沫,就能保證通信不會被竊聽燥翅,因為中間人沒有私鑰,無法解開通過公鑰加密的數(shù)據(jù)蜕提。
            NSUInteger trustedPublicKeyCount = 0;
            // 從serverTrust中取出服務器端傳過來的所有可用的證書森书,并依次得到相應的公鑰
            NSArray *publicKeys = AFPublicKeyTrustChainForServerTrust(serverTrust);

            for (id trustChainPublicKey in publicKeys) {
                for (id pinnedPublicKey in self.pinnedPublicKeys) {
                    // 遍歷服務端的公鑰和本地的公鑰,看是否有相同的
                    if (AFSecKeyIsEqualToKey((__bridge SecKeyRef)trustChainPublicKey, (__bridge SecKeyRef)pinnedPublicKey)) {
                        trustedPublicKeyCount += 1;
                    }
                }
            }
            // 有相同就返回YES
            return trustedPublicKeyCount > 0;
        }
    }

    return NO;
}

大體邏輯是:

  • 給系統(tǒng)設置驗證策略谎势,AFSSLPinningModeNone模式下如果設置了允許無效證書凛膏,就返回YES,否則根據(jù)證書驗證情況來返回脏榆。
  • 其它模式下猖毫,如果沒有允許無效證書,先以系統(tǒng)中的CA根證書為錨點證書來驗證须喂, 如果沒有設置允許無效證書吁断,并且證書也無效趁蕊,就返回NO。
  • AFSSLPinningModeCertificate模式下仔役,先把pinnedCertificates中的證書設置為錨點證書掷伙,然后使用導入的錨點證書來驗證(即用本地證書驗證服務器證書),如果驗證通過就獲取服務器證書的證書鏈骂因,看本地證書是否包含證書鏈中的證書炎咖,包含就返回YES赃泡。
  • AFSSLPinningModePublicKey模式下寒波,只驗證服務器返回證書的公鑰,不驗證其它信息升熊。

其中錨點證書是系統(tǒng)信任的證書俄烁。

iOS下訪問https的方法

訪問https分兩種情況:

  • 1、如果請求的https的證書是國際公認可靠CA頒發(fā)的级野,那么NSURLSession內部會通過驗證页屠,不會走代理方法,這時不論使用系統(tǒng)的NSURLSession還是AFNetworking蓖柔,都不需要額外代碼辰企,與http請求代碼完全相同。
  • 2况鸣、如果使用自簽名的證書牢贸,則需要實現(xiàn)代理方法,如果是iOS9以上镐捧,還要設置Allow Arbitrary Loads為YES潜索。

1.使用蘋果的NSURLSession進行自簽名證書驗證

// 需要導入該頭文件
#import <AssertMacros.h>
// 聲明屬性
@property (nonatomic, assign) BOOL notValidatesSSL; // 不驗證SSL證書
@property (nonatomic, assign) BOOL validatesDomainName; // 驗證域名
@property (nonatomic, assign) BOOL allowInvalidCertificates; // 允許自簽名證書
@property (nonatomic, strong) NSSet <NSData *> *pinnedCertificates;

- (void)configWithValidateSSL:(BOOL)validate {
    if (validate) {
        NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"12306.cer" ofType:nil];
        NSData *cerData = [NSData dataWithContentsOfFile:cerPath];
        NSSet *cers = [[NSSet alloc] initWithObjects:cerData, nil];
        self.pinnedCertificates = cers;
        self.notValidatesSSL = NO;
        self.validatesDomainName = YES;
        self.allowInvalidCertificates = YES;
    } else {
        self.notValidatesSSL = YES;
        self.validatesDomainName = NO;
        self.allowInvalidCertificates = YES;
    }
}
- (void)viewDidLoad {
    [super viewDidLoad];
    // 驗證證書
    [self configWithValidateSSL:YES];

    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[[NSOperationQueue alloc] init]];
    NSURLSessionDataTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://kyfw.12306.cn/otn/login/init"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (error) {
            NSLog(@"error:%@",error);
        } else {
            NSLog(@"response:%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
        }
    }];
    [task resume];
}
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler {

    NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
    __block NSURLCredential *credential = nil;

    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        if ([self evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host certificates:self.pinnedCertificates]) {
            // 如果驗證通過,則通過challenge.protectionSpace.serverTrust創(chuàng)建一個新憑據(jù)懂酱,供NSURLSession判斷
            disposition = NSURLSessionAuthChallengeUseCredential;
            credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
        } else {
            // 如果驗證不通過竹习,則取消此次網絡請求
            disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
        }
    } else {
        // 如果驗證方法不是ServerTrust,則使用默認的方式處理
        disposition = NSURLSessionAuthChallengePerformDefaultHandling;
    }
    if (completionHandler) {
        completionHandler(disposition, credential);
    }
}

- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(NSString *)domain certificates:(NSSet <NSData *> *)certificates {
    if (domain && self.allowInvalidCertificates && self.validatesDomainName && (self.notValidatesSSL == YES || self.pinnedCertificates.count == 0)) {
        return NO;
    }
    
    // 設置驗證策略
    NSMutableArray *policies = [NSMutableArray array];
    [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)];
    SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);
    
    if (!ServerTrustIsValid(serverTrust) && !self.allowInvalidCertificates) {
        return NO;
    }
    
    // 開始驗證
    if (self.notValidatesSSL == YES) {
        return self.allowInvalidCertificates || ServerTrustIsValid(serverTrust);
    } else if (!ServerTrustIsValid(serverTrust) && !self.allowInvalidCertificates) {
        return NO;
    }
    
    NSMutableArray *pinnedCertificates = [NSMutableArray array];
    for (NSData *certificateData in certificates) {
        [pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)];
    }
    SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates);
    
    if (!ServerTrustIsValid(serverTrust)) {
        return NO;
    }
    
    NSArray *serverCertificates = CertificateTrustChainForServerTrust(serverTrust);
    
    for (NSData *trustChainCertificate in [serverCertificates reverseObjectEnumerator]) {
        // 查看是否與證書鏈中的證書匹配
        if ([certificates containsObject:trustChainCertificate]) {
            return YES;
        }
    }
    
    return NO;
}

static BOOL ServerTrustIsValid(SecTrustRef serverTrust) {
    BOOL isValid = NO;
    SecTrustResultType result;
    
    __Require_noErr_Quiet(SecTrustEvaluate(serverTrust, &result), _out);
    
    isValid = (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed);
    
_out:
    return isValid;
}

static NSArray * CertificateTrustChainForServerTrust(SecTrustRef serverTrust) {
    CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust);
    NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:(NSUInteger)certificateCount];
    
    for (CFIndex i = 0; i < certificateCount; i++) {
        SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i);
        [trustChain addObject:(__bridge_transfer NSData *)SecCertificateCopyData(certificate)];
    }
    
    return [NSArray arrayWithArray:trustChain];
}

2.AFNetworking進行自簽名證書驗證
方法一列牺、將自簽名證書導入項目中進行校驗

NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"kyfw.12306.cn.cer" ofType:nil];
NSData *cerData = [NSData dataWithContentsOfFile:cerPath];
NSSet *set = [[NSSet alloc] initWithObjects:cerData, nil];

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
// 設置SSLPinningMode整陌,并傳入證書
manager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:set];
// 設置允許自簽名證書
manager.securityPolicy.allowInvalidCertificates = YES;
[manager GET:@"https://kyfw.12306.cn/otn/login/init" parameters:nil progress:^(NSProgress * _Nonnull downloadProgress) {

} success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
    NSLog(@"%@", responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {

}];

證書導入項目后,將證書傳入AFSecurityPolicy瞎领,allowInvalidCertificates設為YES泌辫,SSLPinningMode設為AFSSLPinningModeCertificate,AF內部就會進行驗證默刚。

方法二甥郑、不進行驗證,可訪問所有https網站

AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
// 設置不驗證域名且允許無效證書
// 這時-evaluateServerTrust:forDomain:方法不會進行驗證而直接返回YES
manager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
manager.securityPolicy.validatesDomainName = NO;
manager.securityPolicy.allowInvalidCertificates = YES;
[manager GET:@"https://kyfw.12306.cn/otn/login/init" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
    NSLog(@"%@", responseObject);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {

}];

設置validatesDomainName為NO荤西,allowInvalidCertificates為YES澜搅。設置PinningModeAFSSLPinningModeNone表示不驗證SSL證書伍俘,validatesDomainName表示是否需要驗證域名,默認為YES勉躺, 如果要忽略本地證書(或本地無證書)癌瘾,就把它設為NO。 allowInvalidCertificates 表示是否允許無效證書(也就是自建的證書)饵溅,默認為NO妨退,當它設為YES時,AF內部不管證書是否可靠蜕企,都直接返回驗證通過咬荷。

參考文章:
《iOS中對HTTPS證書鏈的驗證》
《iOS安全系列之一:HTTPS》
《iOS安全系列之二:HTTPS進階》
《AFN-HTTPS訪問控制》
《寫給iOS開發(fā)者的HTTPS指南》

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市轻掩,隨后出現(xiàn)的幾起案子幸乒,更是在濱河造成了極大的恐慌,老刑警劉巖唇牧,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件罕扎,死亡現(xiàn)場離奇詭異,居然都是意外死亡丐重,警方通過查閱死者的電腦和手機腔召,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來扮惦,“玉大人臀蛛,你說我怎么就攤上這事【睹澹” “怎么了掺栅?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長纳猪。 經常有香客問我氧卧,道長,這世上最難降的妖魔是什么氏堤? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任沙绝,我火速辦了婚禮,結果婚禮上鼠锈,老公的妹妹穿的比我還像新娘闪檬。我一直安慰自己,他們只是感情好购笆,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布粗悯。 她就那樣靜靜地躺著,像睡著了一般同欠。 火紅的嫁衣襯著肌膚如雪样傍。 梳的紋絲不亂的頭發(fā)上横缔,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機與錄音衫哥,去河邊找鬼茎刚。 笑死,一個胖子當著我的面吹牛撤逢,可吹牛的內容都是我干的膛锭。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蚊荣,長吁一口氣:“原來是場噩夢啊……” “哼初狰!你這毒婦竟也來了?” 一聲冷哼從身側響起妇押,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤跷究,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后敲霍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡丁存,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年肩杈,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片解寝。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡扩然,死狀恐怖,靈堂內的尸體忽然破棺而出聋伦,到底是詐尸還是另有隱情夫偶,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布觉增,位于F島的核電站兵拢,受9級特大地震影響,放射性物質發(fā)生泄漏逾礁。R本人自食惡果不足惜说铃,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望嘹履。 院中可真熱鬧腻扇,春花似錦、人聲如沸砾嫉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽焕刮。三九已至舶沿,卻和暖如春舌剂,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背暑椰。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工霍转, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人一汽。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓避消,卻偏偏與公主長得像,于是被迫代替她去往敵國和親召夹。 傳聞我的和親對象是個殘疾皇子岩喷,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內容