本文由我們團隊的美女 超哥 分享
HTTPS從最終的資料解析的角度,與HTTP相同。HTTPS將HTTP協議資料包放到SSL/TSL層加密後,在TCP/IP層組成IP資料包去傳輸,以此保證傳輸資料的安全;而對於接收端,在SSL/TSL將接收的資料包解密之後,將資料傳給HTTP協議層。
SSL/TSL包括四次握手,主要交換三個資訊:
- 數字證書;
- 三個隨機數;
- 加密通訊協議。
其通訊過程如下示意圖:
數字證書
該證書一般是由伺服器發給客戶端,接收方通過驗證這個證書是不是由信賴的CA簽發,或者與本地的證書相對比,來判斷證書是否可信;假如需要雙向驗證,則伺服器和客戶端都需要傳送數字證書給對方驗證。
數字證書的生成是分層級的,從葉節點證書往根證書層層驗證(有效期、簽名等等),遇到根證書時,發現作為可信錨點的它存在與可信證書列表中,那麼驗證就通過。例如在鑰匙串中可以看到某券商公司申請的證書沒有在系統可信任的證書列表中。
下面以某浪sdk裡的證書為代表簡單說明一下數字證書的內容:
證書欄位 | 證書說明 |
---|---|
簽發者名稱 | 釋出並簽署該證書的實體的資訊 |
序列號 | 數字證書機構(Certificate Authority, CA)給證書的唯一整數,一個數字證書一個序列號 |
主題名稱 | 用於識別該數字證書的資訊 |
公共金鑰資訊 | 可公開的金鑰資訊 |
簽名 | 通過簽名演算法計算證書內容後得到的資料,用於驗證證書是否被篡改 |
三個隨機數
這三個隨機數構成了後續通訊過程中用來對資料進行對稱加密解密的“對話金鑰”。首先客戶端先發第一個隨機數n1,然後伺服器返回第二個隨機數n2(這個過程同時把數字證書發給客戶端),這兩個隨機數都是明文的;而第三個隨機數n3,客戶端用數字證書的公鑰進行非對稱加密,發給伺服器;而伺服器用只有自己知道的私鑰來解密,獲取第三個隨機數。服務端和客戶端都有了三個隨機數n1+n2+n3後,兩端就使用這三個隨機數來生成“對話金鑰”,在此之後的通訊就使用這個“對話金鑰”來進行對稱加解密。
加密通訊協議
雙方商量具體使用哪一種加密方式,假如兩者支援的加密方式不匹配,則無法進行通訊。因為這個過程中,服務端的私鑰只用來解密第三個隨機數,從來沒有在網路中傳輸過,只要私鑰沒有被洩露,那麼資料就是安全的。
下邊主要介紹一下NSURLConnection
支援HTTPS的實現設定證書作為可信的錨點程式碼應用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
// SDWebImageDownloaderOperation (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge{ //通過 challenge.protectionSpace.authenticationMethod 取得保護空間要求我們認證的方式 if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { if (!(self.options & SDWebImageDownloaderAllowInvalidSSLCertificates) && [challenge.sender respondsToSelector:@selector(performDefaultHandlingForAuthenticationChallenge:)]) { [challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge]; } else { NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; } } else { if ([challenge previousFailureCount] == 0) { if (self.credential) { [[challenge sender] useCredential:self.credential forAuthenticationChallenge:challenge]; } else { [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge]; } } else { [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge]; } } } |
StockPromotionViewController
在webview
中使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { NSString* scheme = [[request URL] scheme]; //判斷是不是https if ([scheme isEqualToString:@"https"]) { if (self.authed) { return YES; } NSURLConnection* conn = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL:request.URL] delegate:self]; [conn start]; [webView stopLoading]; return NO; } return YES; } - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge { if ([challenge previousFailureCount]== 0) { self.authed = YES; //NSURLCredential 這個類是表示身份驗證憑據不可變物件。憑證的實際型別宣告的類的建構函式來確定。回撥中會收到一個challenge NSURLCredential* cre = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; [challenge.sender useCredential:cre forAuthenticationChallenge:challenge]; } } - (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response { return request; } - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { self.authed = YES; //webview 重新載入請求。 [self.webView loadRequest:[NSURLRequest requestWithURL:connection.currentRequest.URL]]; [connection cancel]; } |