AFSecurityPolicy用於驗證HTTPS請求的證書,先來看看HTTPS的原理和證書相關的幾個問題。html
HTTPS鏈接創建過程大體是,客戶端和服務端創建一個鏈接,服務端返回一個證書,客戶端裏存有各個受信任的證書機構根證書,用這些根證書對服務端返回的證書進行驗證,經驗證若是證書是可信任的,就生成一個pre-master secret,用這個證書的公鑰加密後發送給服務端,服務端用私鑰解密後獲得pre-master secret,再根據某種算法生成master secret,客戶端也一樣根據這種算法從pre-master secret生成master secret,隨後雙方的通訊都用這個master secret對傳輸數據進行加密解密。
git
以上是簡單過程,中間還有不少細節,詳細過程和原理已經有不少文章闡述得很好,就再也不復述,推薦一些相關文章:
關於非對稱加密算法的原理:RSA算法原理<一> <二>
關於整個流程:HTTPS那些事<一> <二> <三>
關於數字證書:淺析數字證書github
這裏說下一開始我比較費解的兩個問題:算法
首先要知道非對稱加密算法的特色,非對稱加密有一對公鑰私鑰,用公鑰加密的數據只能經過對應的私鑰解密,用私鑰加密的數據只能經過對應的公鑰解密。瀏覽器
咱們來看最簡單的狀況:一個證書頒發機構(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公鑰解密,因此僞造的證書確定沒法經過驗證。架構
能夠理解爲證書綁定,是指客戶端直接保存服務端的證書,創建https鏈接時直接對比服務端返回的和客戶端保存的兩個證書是否同樣,同樣就代表證書是真的,再也不去系統的信任證書機構裏尋找驗證。這適用於非瀏覽器應用,由於瀏覽器跟不少未知服務端打交道,沒法把每一個服務端的證書都保存到本地,但CS架構的像手機APP事先已經知道要進行通訊的服務端,能夠直接在客戶端保存這個服務端的證書用於校驗。post
爲何直接對比就能保證證書沒問題?若是中間人從客戶端取出證書,再假裝成服務端跟其餘客戶端通訊,它發送給客戶端的這個證書不就能經過驗證嗎?確實能夠經過驗證,但後續的流程走不下去,由於下一步客戶端會用證書裏的公鑰加密,中間人沒有這個證書的私鑰就解不出內容,也就截獲不到數據,這個證書的私鑰只有真正的服務端有,中間人僞造證書主要僞造的是公鑰。網站
爲何要用SSL Pinning?正常的驗證方式不夠嗎?若是服務端的證書是從受信任的的CA機構頒發的,驗證是沒問題的,但CA機構頒發證書比較昂貴,小企業或我的用戶可能會選擇本身頒發證書,這樣就沒法經過系統受信任的CA機構列表驗證這個證書的真僞了,因此須要SSL Pinning這樣的方式去驗證。
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分三種驗證模式:
這個模式表示不作SSL pinning,只跟瀏覽器同樣在系統的信任機構列表裏驗證服務端返回的證書。若證書是信任機構簽發的就會經過,如果本身服務器生成的證書,這裏是不會經過的。
這個模式表示用證書綁定方式驗證證書,須要客戶端保存有服務端的證書拷貝,這裏驗證分兩步,第一步驗證證書的域名/有效期等信息,第二步是對比服務端返回的證書跟客戶端返回的是否一致。
這裏還沒弄明白第一步的驗證是怎麼進行的,代碼上跟去系統信任機構列表裏驗證同樣調用了SecTrustEvaluate,只是這裏的列表換成了客戶端保存的那些證書列表。若要驗證這個,是否應該把服務端證書的頒發機構根證書也放到客戶端裏?
這個模式一樣是用證書綁定方式驗證,客戶端要有服務端的證書拷貝,只是驗證時只驗證證書裏的公鑰,不驗證證書的有效期等信息。只要公鑰是正確的,就能保證通訊不會被竊聽,由於中間人沒有私鑰,沒法解開經過公鑰加密的數據。
整個AFSecurityPolicy就是實現這這幾種驗證方式,剩下的就是實現細節了,詳見源碼。