SSLPinning 延伸


AFSecurityPolicy用於驗證HTTPS請求的證書,先來看看HTTPS的原理和證書相關的幾個問題。

HTTPS

HTTPS連接建立過程大致是,客戶端和服務端建立一個連接,服務端返回一個證書,客戶端里存有各個受信任的證書機構根證書,用這些根證書對服務端返回的證書進行驗證,經驗證如果證書是可信任的,就生成一個pre-master secret,用這個證書的公鑰加密后發送給服務端,服務端用私鑰解密后得到pre-master secret,再根據某種算法生成master secret,客戶端也同樣根據這種算法從pre-master secret生成master secret,隨后雙方的通信都用這個master secret對傳輸數據進行加密解密。

以上是簡單過程,中間還有很多細節,詳細過程和原理已經有很多文章闡述得很好,就不再復述,推薦一些相關文章:
關於非對稱加密算法的原理:RSA算法原理<一> <二>
關於整個流程:HTTPS那些事<一> <二> <三>
關於數字證書:淺析數字證書

這里說下一開始我比較費解的兩個問題:

1.證書是怎樣驗證的?怎樣保證中間人不能偽造證書?

首先要知道非對稱加密算法的特點,非對稱加密有一對公鑰私鑰,用公鑰加密的數據只能通過對應的私鑰解密,用私鑰加密的數據只能通過對應的公鑰解密。

我們來看最簡單的情況:一個證書頒發機構(CA),頒發了一個證書A,服務器用這個證書建立https連接。客戶端在信任列表里有這個CA機構的根證書。

首先CA機構頒發的證書A里包含有證書內容F,以及證書加密內容F1,加密內容F1就是用這個證書機構的私鑰對內容F加密的結果。(這中間還有一次hash算法,略過。)

建立https連接時,服務端返回證書A給客戶端,客戶端的系統里的CA機構根證書有這個CA機構的公鑰,用這個公鑰對證書A的加密內容F1解密得到F2,跟證書A里內容F對比,若相等就通過驗證。整個流程大致是:F->CA私鑰加密->F1->客戶端CA公鑰解密->F。因為中間人不會有CA機構的私鑰,客戶端無法通過CA公鑰解密,所以偽造的證書肯定無法通過驗證。

2.什么是SSL Pinning?

可以理解為證書綁定,是指客戶端直接保存服務端的證書,建立https連接時直接對比服務端返回的和客戶端保存的兩個證書是否一樣,一樣就表明證書是真的,不再去系統的信任證書機構里尋找驗證。這適用於非瀏覽器應用,因為瀏覽器跟很多未知服務端打交道,無法把每個服務端的證書都保存到本地,但CS架構的像手機APP事先已經知道要進行通信的服務端,可以直接在客戶端保存這個服務端的證書用於校驗。

為什么直接對比就能保證證書沒問題?如果中間人從客戶端取出證書,再偽裝成服務端跟其他客戶端通信,它發送給客戶端的這個證書不就能通過驗證嗎?確實可以通過驗證,但后續的流程走不下去,因為下一步客戶端會用證書里的公鑰加密,中間人沒有這個證書的私鑰就解不出內容,也就截獲不到數據,這個證書的私鑰只有真正的服務端有,中間人偽造證書主要偽造的是公鑰。

為什么要用SSL Pinning?正常的驗證方式不夠嗎?如果服務端的證書是從受信任的的CA機構頒發的,驗證是沒問題的,但CA機構頒發證書比較昂貴,小企業或個人用戶可能會選擇自己頒發證書,這樣就無法通過系統受信任的CA機構列表驗證這個證書的真偽了,所以需要SSL Pinning這樣的方式去驗證。

AFSecurityPolicy

NSURLConnection已經封裝了https連接的建立、數據的加密解密功能,我們直接使用NSURLConnection是可以訪問https網站的,但NSURLConnection並沒有驗證證書是否合法,無法避免中間人攻擊。要做到真正安全通訊,需要我們手動去驗證服務端返回的證書,AFSecurityPolicy封裝了證書驗證的過程,讓用戶可以輕易使用,除了去系統信任CA機構列表驗證,還支持SSL Pinning方式的驗證。使用方法:

1
2
3
4
5
6
7
//把服務端證書(需要轉換成cer格式)放到APP項目資源里,AFSecurityPolicy會自動尋找根目錄下所有cer文件
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey];
securityPolicy.allowInvalidCertificates = YES ;
[AFHTTPRequestOperationManager manager].securityPolicy = securityPolicy;
[manager GET: @"https://example.com/" parameters: nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];

AFSecurityPolicy分三種驗證模式:

AFSSLPinningModeNone

這個模式表示不做SSL pinning,只跟瀏覽器一樣在系統的信任機構列表里驗證服務端返回的證書。若證書是信任機構簽發的就會通過,若是自己服務器生成的證書,這里是不會通過的。

AFSSLPinningModeCertificate

這個模式表示用證書綁定方式驗證證書,需要客戶端保存有服務端的證書拷貝,這里驗證分兩步,第一步驗證證書的域名/有效期等信息,第二步是對比服務端返回的證書跟客戶端返回的是否一致。

這里還沒弄明白第一步的驗證是怎么進行的,代碼上跟去系統信任機構列表里驗證一樣調用了SecTrustEvaluate,只是這里的列表換成了客戶端保存的那些證書列表。若要驗證這個,是否應該把服務端證書的頒發機構根證書也放到客戶端里?

AFSSLPinningModePublicKey

這個模式同樣是用證書綁定方式驗證,客戶端要有服務端的證書拷貝,只是驗證時只驗證證書里的公鑰,不驗證證書的有效期等信息。只要公鑰是正確的,就能保證通信不會被竊聽,因為中間人沒有私鑰,無法解開通過公鑰加密的數據。

整個AFSecurityPolicy就是實現這這幾種驗證方式,剩下的就是實現細節了,詳見源碼。

源碼注釋


免責聲明!

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



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