通過Authentication Challenge來信任自簽名Https證書


在開發階段我們我們經常使用自簽名的證書來部署我們的后台rest api。但是在iOS中調用的時候就會因為證書不被信任而調用api不成功。這時候我們就需要通過實現某些網絡回調函數來自定義證書的驗證邏輯。(在iOS中一般通過UrlSession(OC中是NSUrlSession)來進行網絡通信,這里以UrlSession為例)。首先我們需要了解幾個概念。

Challenge     

Challenge是計算機安全中的專業術語。字面意思質詢。就是為了驗證用戶身份,向訪問者發送一個質詢,然后訪問者需要提供一個正確的回答以示身份。最簡單的就是我們訪問一個需要授權的網站,網站后台會通過HTTP協議想瀏覽器發送一個質詢,要求用戶輸入用戶名密碼。(瀏覽器會彈出一個對話框供用戶輸入)

在iOS的網絡相關庫中,提供了如下幾個類來描述Challenge的過程中的抽象實體。

URLProtectionSpace

這個表示服務器上的一塊受保護的區域,訪問這一塊需要進行質詢。他有如下常用屬性:

// realm是ProtectionSpace的標示符,服務器上的一組資源通過realm來標示成一組采用相同驗證方式的資源(ProtectionSpace)。
@property (nullable, readonly, copy) NSString *realm;
// 資源所在的服務器
@property (readonly, copy) NSString *host;
// 資源所在服務器端口
@property (readonly) NSInteger port;
//獲取資源的協議資源
@property (nullable, readonly, copy) NSString *protocol;
// 質詢所采用驗證方式
@property (readonly, copy) NSString *authenticationMethod;

質詢驗證方式有如下幾種是常用的:

NSURLAuthenticationMethodHTTPBasic //HTTP基本驗證,服務器向客戶端詢問用戶名,密碼

NSURLAuthenticationMethodClientCertificate//客戶端證書驗證,服務器向客戶端詢客戶端身份證書

NSURLAuthenticationMethodServerTrust//服務器端證書驗證,客戶端對服務器端的證書進行驗證。HTTPS中的服務器端證書驗證屬於這一種。

URLAuthenticationChallenge

這就是服務器端對客戶端的一次質詢的描述了。它有如下常用屬性:

//該質詢所對應的ProtectionSpace
@property (readonly, copy) NSURLProtectionSpace *protectionSpace;

//表示該質詢的發送方
@property (nullable, readonly, retain) id<NSURLAuthenticationChallengeSender> sender;

UrlCredential       

他是客戶端對服務器端質詢的響應。根據驗證方式不一樣,有如下幾種UrlCredential:

  • 基於用戶名密碼的UrlCredential
  • 基於客戶端證書的UrlCredential
  • 基於服務器端證書的UrlCredential //就是我們這里驗證服務器端的證書要用到的

它們分別對應於UrlCredential的三種構造方式。詳情參考Apple開發文檔

SecTrust         

 

他是iOS中對證書和Accept Policy的包裝。系統對后台證書驗證實際上是對該對象的驗證。詳情建Apple開發文檔

好了,到這里所有的概念性的東西都說完了。最后就是要把這些概念全部組合到UrlSession的一個回調方法中來自行驗證證書。代碼如下:

//這是NSUrlSessionDelegate總定義的函數,因此先需要設置NSUrlSession對象的delegate,然后再delegate對象中實現該方法
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {
  //這里檢查質詢的驗證方式是否是服務器端證書驗證 if([challenge.protectionSpace.authenticationMethod isEqualToString: NSURLAuthenticationMethodServerTrust]) {
     //這里直接把證書包裝對象拿到, SecTrustRef trustRef
= [challenge.protectionSpace serverTrust];
     // 使用證書SecTrust對象來構造URLCredential,系統默認實現這里應該是要對SecTrust進行驗證,而此處我們的目的就是要信任所有證書。因此跳過驗證這一步。
id trustCredential = [NSURLCredential credentialForTrust:trustRef];
     //通過回調函數告訴系統對於該質詢的UrlCredential. completionHandler(NSURLSessionAuthChallengeUseCredential, trustCredential); }
else { completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); } }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM