本文主要講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ù):challenge
和completionHandler
拨匆。
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澜搅。設置PinningMode
為AFSSLPinningModeNone
表示不驗證SSL證書伍俘,validatesDomainName表示是否需要驗證域名,默認為YES勉躺, 如果要忽略本地證書(或本地無證書)癌瘾,就把它設為NO。 allowInvalidCertificates 表示是否允許無效證書(也就是自建的證書)饵溅,默認為NO妨退,當它設為YES時,AF內部不管證書是否可靠蜕企,都直接返回驗證通過咬荷。
參考文章:
《iOS中對HTTPS證書鏈的驗證》
《iOS安全系列之一:HTTPS》
《iOS安全系列之二:HTTPS進階》
《AFN-HTTPS訪問控制》
《寫給iOS開發(fā)者的HTTPS指南》