1. 程式人生 > >iOS中HTTPS證書驗證淺析

iOS中HTTPS證書驗證淺析

本文來自於騰訊Bugly公眾號(weixinBugly),原文地址:https://mp.weixin.qq.com/s/-fLLTtip509K6pNOTkflPQ
我是帶著一系列的問題,找到了這篇文章,很好地解答我的疑惑!
1.怎麼抓HTTPS的包?
2.中間人攻擊是什麼?解決方案?
3.https通訊的話,程式碼怎麼實現CA證書校驗?
4.CA證書校驗都有哪些型別可以檢驗 ?

本文分為三部分:
* 分析下對伺服器身份驗證的完整握手過程
* 證書鏈的驗證
* 探索iOS中原生庫NSURLConnection或NSURLSession如何支援實現https。

通常我們會訪問

HTTPS://xxx的網站,當你在瀏覽器位址列輸入支援HTTPS協議的URL地址後,伺服器返回的資料會顯示在頁面上。對於不瞭解HTTPS協議工作原理的小夥伴可能覺得這個過程很簡單:傳送請求-伺服器響應請求-結果返回並顯示。但對於HTTPS而言,在整個傳送請求返回資料過程中還涉及到通訊雙方證書驗證、資料加密、資料完整性校驗等。

引入HTTPS是為了解決HTTP所帶來的三個問題:
* HTTP是明文傳輸,資料容易被竊取,因此要加密資料以防止資料中途竊取
* 認證伺服器身份,確保資料傳送到正確的伺服器
* 維護資料的完整性,防止資料在傳輸中被改變,如中間人攻擊

下面以登入qq郵箱為例,通過Wireshark抓包可以看到如下圖:
這裡寫圖片描述


從圖中可以看到:在瀏覽器與伺服器進行傳輸通訊資料之前,還經歷了Client Hello-Server Hello-Client Key Exchange-Change Cipher Spec等過程。

上述單向驗證的完整握手過程,總結如下:
這裡寫圖片描述

第一階段:ClientHello
客戶端發起請求,以明文傳輸請求資訊,包含版本資訊,加密套件候選列表,壓縮演算法候選列表,隨機數random_C,擴充套件欄位等資訊。

第二階段:ServerHello-ServerHelloDone
如上圖可以看出這個階段包含4個過程( 有的伺服器是單條傳送,有的是合併一起傳送)。服務端返回協商的資訊結果,包括選擇使用的協議版本,選擇的加密套件,選擇的壓縮演算法、隨機數random_S等,其中隨機數用於後續的金鑰協商。伺服器也會配置並返回對應的證書鏈Certificate,用於身份驗證與金鑰交換。然後會發送ServerHelloDone資訊用於通知伺服器資訊傳送結束。

第三階段:證書校驗
在上圖中的5-6之間,客戶端這邊還需要對伺服器返回的證書進行校驗。只有證書驗證通過後,才能進行後續的通訊。(具體分析可參看後續的證書驗證過程)

第四階段:ClientKeyExchange-Finished
伺服器返回的證書驗證合法後, 客戶端計算產生隨機數字Pre-master,並用server證書中公鑰加密,傳送給伺服器。同時客戶端會根據已有的三個隨機數根據相應的生成協商金鑰。客戶端會通知伺服器後續的通訊都採用協商的通訊金鑰和加密演算法進行加密通訊。然後客戶端傳送Finished訊息用於通知客戶端資訊傳送結束。

第五階段:伺服器端生成協商金鑰
伺服器也會根據已有的三個隨機數使用相應的演算法生成協商金鑰,會通知客戶端後續的通訊都採用協商的通訊金鑰和加密演算法進行加密通訊。然後傳送Finished訊息用於通知伺服器資訊傳送結束。

第六階段:握手結束
在握手階段結束後,客戶端和伺服器資料傳輸開始使用協商金鑰進行加密通訊。

總結
簡單來說,HTTPS請求整個過程主要分為兩部分。一是握手過程:用於客戶端和伺服器驗證雙方身份,協商後續資料傳輸時使用到的金鑰等。二是資料傳輸過程:身份驗證通過並協商好金鑰後,通訊雙方使用協商好的金鑰加密資料並進行通訊。在握手過程協商金鑰時,使用的是非對稱金鑰交換演算法, 金鑰交換演算法本身非常複雜,金鑰交換過程涉及到隨機數生成,模指數運算,空白補齊,加密,簽名等操作。在資料傳輸過程中,客戶端和伺服器端使用協商好的金鑰進行對稱加密解密。

證書

PKI (Public Key Infrastructure),公開金鑰基礎設施。它是一個標準,在這個標準之下發展出的為了實現安全基礎服務目的的技術統稱為PKI。 權威的第三方機構CA(認證中心)是PKI的核心, CA負責核實公鑰的擁有者的資訊,並頒發認證”證書”,同時能夠為使用者提供證書驗證服務。 x.509是PKI中最重要的標準,它定義了公鑰證書的基本結構。

證書申請過程

證書申請者向頒發證書的可信第三方CA提交申請證書相關資訊,包括:申請者域名、申請者生成的公鑰(私鑰自己儲存)及證書請求檔案.cer等

CA通過線上、線下等多種手段驗證證書申請者提供的資訊合法和真實性。

當證書申請者提供的資訊稽核通過後,CA向證書申請者頒發證書,證書內容包括明文資訊和簽名信息。其中明文資訊包括證書頒發機構、證書有效期、域名、申請者相關資訊及申請者公鑰等,簽名信息是使用CA私鑰進行加密的明文資訊。當證書申請者獲取到證書後,可以通過安裝的CA證書中的公鑰對簽名信息進行解密並與明文資訊進行對比來驗證簽名的完整性。

證書驗證過程:
驗證證書本身的合法性(驗證簽名完整性,驗證證書有效期等)
驗證證書頒發者的合法性(查詢頒發者的證書並檢查其合法性,這個過程是遞迴的)
證書驗證的遞迴過程最終會成功終止,而成功終止的條件是:證書驗證過程中遇到了錨點證書,錨點證書通常指:嵌入到作業系統中的根證書(權威證書頒發機構頒發的自簽名證書)。

證書驗證失敗的原因
1.無法找到證書的頒發者
2.證書過期
3.驗證過程中遇到了自簽名證書,但該證書不是錨點證書。
4.無法找到錨點證書(即在證書鏈的頂端沒有找到合法的根證書)
5.訪問的server的dns地址和證書中的地址不同

iOS實現支援HTTPS

在OC中當使用NSURLConnection或NSURLSession建立URL並向伺服器傳送https請求獲取資源時,伺服器會使用HTTP狀態碼401進行響應(即訪問拒絕)。此時NSURLConnection或NSURLSession會接收到伺服器需要授權的響應,當客戶端授權通過後,才能繼續從伺服器獲取資料。如下圖所示:
這裡寫圖片描述

非自簽名證書驗證實現

在接收到伺服器返回的狀態碼為401的響應後,對於NSURLSession而言,需要代理物件實現URLSession:task:didReceiveChallenge:completionHandler:方法。對於NSURLConnection而言,需要代理物件實現connection:willSendRequestForAuthenticationChallenge: 方法(OS X v10.7和iOS5及以上),對於早期的版本代理物件需要實現代理物件要實現connection:canAuthenticateAgainstProtectionSpace:和connection:didReceiveAuthenticationChallenge:方法。程式碼如下(參考文件):
這裡寫圖片描述

當客戶端傳送https請求後,伺服器會返回需要授權的相關資訊,然後connection:willSendRequestForAuthenticationChallenge:方法被呼叫。客戶端根據返回的challenge資訊,首先獲取需要驗證的信任物件trust,然後呼叫SecTrustEvaluate方法是用系統預設的驗證方式對信任物件進行驗證,當驗證通過時,使用該信任物件trust生成證書憑證,然後self.connection使用該憑證繼續連線。如下詳解:

NSURLAuthenticationChallenge包含如下資訊:
error :最後一次授權失敗的錯誤資訊
failureResponse :最後一次授權失敗的錯誤資訊
previousFailureCount :授權失敗的次數
proposedCredential :建議使用的證書
protectionSpace :NSURLProtectionSpace物件,代表了伺服器上的一塊需要授權資訊的區域。包括了伺服器地址、埠等資訊。在此指的是challenge.protectionSpace。其中Auth-scheme指protectionSpace所支援的驗證方法,NSURLAuthenticationMethodServerTrust指對protectionSpace執行證書驗證。
這裡寫圖片描述

表示需要驗證的信任物件(Trust Object),在此指的是challenge.protectionSpace.serverTrust。包含待驗證的證書和支援的驗證方法等。

SecTrustRef
表示需要驗證的信任物件(Trust Object),在此指的是challenge.protectionSpace.serverTrust。包含待驗證的證書和支援的驗證方法等。

SecTrustResultType
表示驗證結果。其中 kSecTrustResultProceed表示serverTrust驗證成功,且該驗證得到了使用者認可(例如在彈出的是否信任的alert框中選擇always trust)。 kSecTrustResultUnspecified表示 serverTrust驗證成功,此證書也被暗中信任了,但是使用者並沒有顯示地決定信任該證書。 兩者取其一就可以認為對serverTrust驗證成功。

SecTrustEvaluate
函式內部遞迴地從葉節點證書到根證書驗證。使用系統預設的驗證方式驗證Trust Object,根據上述證書鏈的驗證可知,系統會根據Trust Object的驗證策略,一級一級往上,驗證證書鏈上每一級證書有效性。

NSURLCredential
表示身份驗證證書。URL Lodaing支援3種類型證書:password-based user credentials, certificate-based user credentials, 和certificate-based server credentials(需要驗證伺服器身份時使用)。因此NSURLCredential可以表示由使用者名稱/密碼組合、客戶端證書及伺服器信任建立的認證資訊,適合大部分的認證請求。對於NSURLCredential也存在三種持久化機制:

NSURLCredentialPersistenceNone :要求 URL 載入系統 “在用完相應的認證資訊後立刻丟棄”。
NSURLCredentialPersistenceForSession :要求 URL 載入系統 “在應用終止時,丟棄相應的 credential ”。
NSURLCredentialPersistencePermanent :要求 URL 載入系統 “將相應的認證資訊存入鑰匙串(keychain),以便其他應用也能使用。
對於已經驗證通過的信任物件,客戶端也可以不提供證書憑證。

對於NSURLSession,傳遞如下之一的值給completion handler回撥:
NSURLSessionAuthChallengePerformDefaultHandling處理請求,就好像代理沒有提供一個代理方法來處理認證請求
NSURLSessionAuthChallengeRejectProtectionSpace拒接認證請求。基於伺服器響應的認證型別,URL載入類可能會多次呼叫代理方法。
對於 NSURLConnection 和 NSURLDownload,在[challenge sender] 上呼叫continueWithoutCredentialsForAuthenticationChallenge:方法。不提供證書的話,可能會導致連線失敗,呼叫connectionDidFailWithError:方法 ,或者會返回一個不需要驗證身份的替代的URL。 如下程式碼:
這裡寫圖片描述
對於非自簽名的證書,即使伺服器返回的證書是信任的CA頒發的,而為了確定返回的證書正是客戶端需要的證書,這需要本地匯入證書,並將證書設定成需要參與驗證的錨點證書,再呼叫SecTrustEvaluate通過本地匯入的證書來驗證伺服器證書是否是可信的。如果伺服器證書是這個錨點證書對應CA或者子CA頒發的,或伺服器證書本身就是這個錨點證書,則證書信任通過。如下程式碼(參考文件):
這裡寫圖片描述

自簽名證書驗證實現
對於自簽名證書,這樣Trust Object中的伺服器證書是不可信任的CA頒發的,直接使用SecTrustEvaluate驗證是不會成功的。可以採取下述簡單程式碼繞過HTTPS的驗證:
這裡寫圖片描述
上述程式碼一般用於當伺服器使用自簽名證書時,為了方便測試,客戶端可以通過該方法信任所有自簽名證書。

綜上對非自建和自建證書驗證過程的分析,可以總結如下:
1.獲取需要驗證的信任物件(Trust Object)。對於NSURLConnection來說,
是從delegate方法-connection: willSendRequestForAuthenticationChallenge:回調回來的引數challenge中獲取(challenge.protectionSpace.serverTrust) 。
2.使用系統預設驗證方式驗證Trust Object。SecTrustEvaluate會根據Trust Object的驗證策略,一級一級往上,驗證證書鏈上每一級數字簽名的有效性,從而評估證書的有效性。
3.如第二步驗證通過了,一般的安全要求下,就可以直接驗證通過,進入到下一步:使用Trust Object生成一份憑證([NSURLCredential credentialForTrust:serverTrust]),傳入challenge的sender中([challenge.sender useCredential:cred forAuthenticationChallenge:challenge])處理,建立連線。
4.假如有更強的安全要求,可以繼續對Trust Object進行更嚴格的驗證。常用的方式是在本地匯入證書,驗證Trust Object與匯入的證書是否匹配。
5.假如驗證失敗,取消此次Challenge-Response Authentication驗證流程,拒絕連線請求。
6.假如是自建證書的,則不使用第二步系統預設的驗證方式,因為自建證書的根CA的數字簽名未在作業系統的信任列表中。

相關推薦

iOSHTTPS證書驗證淺析

本文來自於騰訊Bugly公眾號(weixinBugly),原文地址:https://mp.weixin.qq.com/s/-fLLTtip509K6pNOTkflPQ 我是帶著一系列的問題,找到了這篇文章,很好地解答我的疑惑! 1.怎麼抓HTTPS的包?

通俗的理解HTTPS以及SSL證書驗證

時間進入到2017年,細心的人在瀏覽器位址列中會發現,經常瀏覽的網站都是https打頭,最左邊也有綠色的安全鎖。其實全站https時代已經來臨。2014年百度完成了全網https的切換,2015年淘寶、天貓頁面全部https訪問,蘋果公司要求2016年底iOS APP實現ht

SVN提示https證書驗證失敗問題svn: E230001: Server SSL certificate verification failed: certificate issued

svn: E230001: Server SSL certificate verification failed: certificate issued 今天在使用svn時候發現出現這個問題,這個是因為證書問題,在終端執行 這個命令是讓忽略證書,然後按提

SVN提示https證書驗證失敗問題

使用svn有時候會出現提示https證書驗證失敗問題,大致問題是什麼"SSL ver failed"什麼的。 問題已經解決了所以沒有保留下來錯誤提示,等下次再出現再傳上來。 解決辦法是在終端介面輸入:svn ls https的svn地址,之後會出現幾個選項,輸入p,回車,即可

OKHttp請求https證書驗證

拿到srca.cer證書放入assets檔案中 private static SSLSocketFactory sslSocketFactory = null; public static void getSocketFactory() { try

iOS HTTPS 證書鏈的驗證

稍微整理了下,共扯了三部分內容: HTTPS 簡要原理;數字證書的內容、生成及驗證;iOS 上對證書鏈的驗證。HTTPS 概要 HTTPS 是執行在 TLS/SSL 之上的 HTTP,與普通的 HTTP 相比,在資料傳輸的安全性上有很大的提升。 要了解它安全性的巧妙之處,需要先簡單地瞭解對稱加密和非對稱加密

iOS UIWebView 訪問https繞過證書驗證的方法

@implementation NSURLRequest (NSURLRequestWithIgnoreSSL) + (BOOL)allowsAnyHTTPSCertificateForHost:(NSString *

iOS開發-https證書驗證

此處博主做一個宣告,如果你想跳過https的雙向驗證,僅僅單向進行直接信任所有的證書,那麼你們的後臺也必須是允許單向驗證的,否則設定了雙向驗證,客戶端是無法跳過的,實在不想當初辛苦的經驗被無知的小白說成無用的垃圾,謝謝。想知道雙向驗證怎麼做的,請在https分類

iOS開發“此證書的簽發者無效”的解決方式

courier data display sina 新浪微博 tracking 項目 text 輸入 iOS開發過程中有時候會出現證書所有變成無效,例如以下圖 然後進行打包的時候會提演示樣例如以下警告: 解決方法: 第一步: 下載ht

HTTPS請求 SSL證書驗證

cer import failed blog kit urllib2 highlight www. header import urllib2 url = "https://www.12306.cn/mormhweb/" headers = {"User-Agent"

iOS內置證書,校驗https請求

har 是否 handle 方法 evaluate 安全 match call request 有些情況處於安全的考慮需要https請求,但是為了防止域名解析很多情況下會使用IP進行訪問。一般的服務不會針對IP去申請證書,所以我們可以自己實現ssl登錄過程,保證請求的安全性

Java訪問HTTPS證書驗證問題

rar html illegal fault tle 包含 verify boolean mitm 為了盡可能避免安全問題,公司的很多系統服務都逐步https化,雖然開始過程會遇到各種問題,但趨勢不改。最完美的https應用是能實現雙向認證,客戶端用私鑰簽名用服務端公鑰加密

https證書驗證過程與生成方法

spec failed hash算法 無法 本地測試 簽名 odin format 內容 1.簡潔的解釋: 1.服務器 用RSA生成公鑰和私鑰2.把公鑰放在證書裏發送給客戶端,私鑰自己保存3.客戶端首先向一個權威的服務器檢查證書的合法性,如果證書合法,客戶端產生一段

fiddler安裝證書進行https協議的抓取

AI ofa sdn net details tar tails get fas 轉自博客 ==>> fiddler中安裝證書進行https協議的抓取fiddler中安裝證書進行https協議的抓取

request發送HTTPS請求(處理SSL證書驗證)

瀏覽器 code erro 發送 傳輸層 查看 抓包 .com tcp連接 1、SSL是什麽,為什麽發送HTTPS請求時需要證書驗證? 1.1 SSL:安全套接字層。是為了解決HTTP協議是明文,避免傳輸的數據被竊取,篡改,劫持等。 1.2 TSL:Tran

TLS/HTTPS 證書生成與驗證

tls協議 形式 用戶輸入 兩臺 node linu get alias acer https://www.cnblogs.com/kyrios/p/tls-and-certificates.html 最近在研究基於ssl的傳輸加密,涉及到了key和證書相關的話題,走了不

iOS開發HTTPS實現之信任SSL證書和自簽名證書

                                          &nb

開發小程式 WAMPApache HTTPS證書詳細配置

由於微信小程式資料獲取url必須為https的路徑,因此需將伺服器部署為https,特此記錄期間踩過的坑。 環境:  - wampserver: 3.0.4_x64_apache2.4.18_mysql5.7.11_php5.6.19-7.0.4 - 系統: 阿里雲 window se

Https優化方案(優化證書驗證篇--OCSP)

一句話概括就是:OCSP 是server 把自己的站點證書和中間證書以及根證書打包一起下發到客戶端,省去客戶端查詢的過程。 OCSP實時查詢會增加客戶端的效能開銷。因此,可以考慮通過OCSP stapling的方案來解決:OCSP stapling是一種允許在TLS握手

處理HTTPS請求 SSL證書驗證

現在隨處可見 https 開頭的網站,urllib2可以為 HTTPS 請求驗證SSL證書,就像web瀏覽器一樣,如果網站的SSL證書是經過CA認證的,則能夠正常訪問,如:https://www.baidu.com/等...如果SSL證書驗證不通過,或者作業系統不信任伺服器的安全證書,比如瀏覽器在訪