如何在iOS上實現對HTTPS的支持(轉)

原文地址:http://blog.5ibc.net/p/101504.htmlhtml

 

首先,須要明確你使用HTTP/HTTPS的用途,由於OSX和iOS平臺提供了多種API,來支持不一樣的用途,官方文檔《Making HTTP and HTTPS Requests》有詳細的說明,而文檔《HTTPS Server Trust Evaluation》則詳細講解了HTTPS驗證相關知識,這裏就很少說了。本文主要講解咱們最經常使用的NSURLConnection支持HTTPS的實現(NSURLSession的實現方法相似,只是要求受權證實的回調不同而已),以及怎麼樣使用AFNetworking這個很是流行的第三方庫來支持HTTPS。本文假設你對HTTP以及NSURLConnection的接口有了足夠的瞭解。安全

1. 驗證證書的API服務器

相關的Api在Security Framework中,驗證流程以下:學習

1). 第一步,先獲取須要驗證的信任對象(Trust Object)。這個Trust Object在不一樣的應用場景下獲取的方式都不同,對於NSURLConnection來講,是從delegate方法-connection:willSendRequestForAuthenticationChallenge:回調回來的參數challenge中獲取([challenge.protectionSpace serverTrust])。google

2). 使用系統默認驗證方式驗證Trust Object。SecTrustEvaluate會根據Trust Object的驗證策略,一級一級往上,驗證證書鏈上每一級數字簽名的有效性(上一部分有講解),從而評估證書的有效性。lua

3). 如第二步驗證經過了,通常的安全要求下,就能夠直接驗證經過,進入到下一步:使用Trust Object生成一份憑證([NSURLCredential credentialForTrust:serverTrust]),傳入challenge的sender中([challenge.sender useCredential:cred forAuthenticationChallenge:challenge])處理,創建鏈接。url

4). 假若有更強的安全要求,能夠繼續對Trust Object進行更嚴格的驗證。經常使用的方式是在本地導入證書,驗證Trust Object與導入的證書是否匹配。更多的方法能夠查看Enforcing Stricter Server Trust Evaluation,這一部分在講解AFNetworking源碼中會講解到。spa

5). 假如驗證失敗,取消這次Challenge-Response Authentication驗證流程,拒絕鏈接請求。操作系統

ps: 假如是自建證書的,則會跳過第二步,使用第三部進行驗證,由於自建證書的根CA的數字簽名未在操做系統的信任列表中。.net

iOS受權驗證的API和流程大概瞭解了,下面,咱們看看在NSURLConnection中的代碼實現:

使用NSURLConnection支持HTTPS的實現

// Now start the connection
NSURL * httpsURL = [NSURL URLWithString:@"https://www.google.com"];
self.connection = [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:httpsURL] delegate:self];
//回調
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    //1)獲取trust object
    SecTrustRef trust = challenge.protectionSpace.serverTrust;
    SecTrustResultType result;
    //2)SecTrustEvaluate對trust進行驗證
    OSStatus status = SecTrustEvaluate(trust, &result);
    if (status == errSecSuccess &&
        (result == kSecTrustResultProceed ||
        result == kSecTrustResultUnspecified)) {
        //3)驗證成功,生成NSURLCredential憑證cred,告知challenge的sender使用這個憑證來繼續鏈接
        NSURLCredential *cred = [NSURLCredential credentialForTrust:trust];
        [challenge.sender useCredential:cred forAuthenticationChallenge:challenge];
    } else {
        //5)驗證失敗,取消此次驗證流程
        [challenge.sender cancelAuthenticationChallenge:challenge];
  }
}

上面是代碼是經過系統默認驗證流程來驗證證書的。假如咱們是自建證書的呢?這樣Trust Object裏面服務器的證書由於不是可信任的CA簽發的,因此直接使用SecTrustEvaluate進行驗證是不會成功。又或者,即便服務器返回的證書是信任CA簽發的,又如何肯定這證書就是咱們想要的特定證書?這就須要先在本地導入證書,設置成須要驗證的Anchor Certificate(就是根證書),再調用SecTrustEvaluate來驗證。代碼以下

//先導入證書
NSString * cerPath = ...; //證書的路徑
NSData * cerData = [NSData dataWithContentsOfFile:cerPath];
SecCertificateRef certificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(cerData));
self.trustedCertificates = @[CFBridgingRelease(certificate)];
//回調
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    //1)獲取trust object
    SecTrustRef trust = challenge.protectionSpace.serverTrust;
    SecTrustResultType result;
    //注意:這裏將以前導入的證書設置成下面驗證的Trust Object的anchor certificate
    SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)self.trustedCertificates);
    //2)SecTrustEvaluate會查找前面SecTrustSetAnchorCertificates設置的證書或者系統默認提供的證書,對trust進行驗證
    OSStatus status = SecTrustEvaluate(trust, &result);
    if (status == errSecSuccess &&
        (result == kSecTrustResultProceed ||
        result == kSecTrustResultUnspecified)) {
        //3)驗證成功,生成NSURLCredential憑證cred,告知challenge的sender使用這個憑證來繼續鏈接
        NSURLCredential *cred = [NSURLCredential credentialForTrust:trust];
        [challenge.sender useCredential:cred forAuthenticationChallenge:challenge];
    } else {
        //5)驗證失敗,取消此次驗證流程
        [challenge.sender cancelAuthenticationChallenge:challenge];
  }
}

建議採用本地導入證書的方式驗證證書,來保證足夠的安全性。更多的驗證方法,請查看官方文檔《HTTPS Server Trust Evaluation》

2. 使用AFNetworking來支持HTTPS

AFNetworking是iOS/OSX開發最流行的第三方開源庫之一,其做者是很是著名的iOS/OSX開發者Mattt Thompson,其博客NSHipster也是iOS/OSX開發者學習和開闊技術視野的好地方。AFNetworking已經將上面的邏輯代碼封裝好,甚至更完善,在AFSecurityPolicy文件中,有興趣能夠閱讀這個模塊的代碼;

AFNetworking上配置對HTTPS的支持很是簡單:

NSURL * url = [NSURL URLWithString:@"https://www.google.com"];
AFHTTPRequestOperationManager * requestOperationManager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:url];
dispatch_queue_t requestQueue = dispatch_create_serial_queue_for_name("kRequestCompletionQueue");
requestOperationManager.completionQueue = requestQueue;
AFSecurityPolicy * securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
//allowInvalidCertificates 是否容許無效證書(也就是自建的證書),默認爲NO
//若是是須要驗證自建證書,須要設置爲YES
securityPolicy.allowInvalidCertificates = YES;
//validatesDomainName 是否須要驗證域名,默認爲YES;
//假如證書的域名與你請求的域名不一致,需把該項設置爲NO
//主要用於這種狀況:客戶端請求的是子域名,而證書上的是另一個域名。由於SSL證書上的域名是獨立的,假如證書上註冊的域名是www.google.com,那麼mail.google.com是沒法驗證經過的;固然,有錢能夠註冊通配符的域名*.google.com,但這個仍是比較貴的。
securityPolicy.validatesDomainName = NO;
//validatesCertificateChain 是否驗證整個證書鏈,默認爲YES
//設置爲YES,會將服務器返回的Trust Object上的證書鏈與本地導入的證書進行對比,這就意味着,假如你的證書鏈是這樣的:
//GeoTrust Global CA 
//    Google Internet Authority G2
//        *.google.com
//那麼,除了導入*.google.com以外,還須要導入證書鏈上全部的CA證書(GeoTrust Global CA, Google Internet Authority G2);
//如是自建證書的時候,能夠設置爲YES,加強安全性;假如是信任的CA所簽發的證書,則建議關閉該驗證;
securityPolicy.validatesCertificateChain = NO;
requestOperationManager.securityPolicy = securityPolicy;

這就是AFNetworking的支持HTTPS的主要配置說明,AFHTTPSessionManager與之基本一致,就不重複了。

3. 總結

從2017年1月起,iOS必須支持HTTPS,因此HTTPS已是大勢所趨了。

相關文章
相關標籤/搜索