在學習 Alamofire
的安全認證以前,咱們先來了解下 HTTPS
。swift
在 HTTP
協議中有可能存在信息竊聽或者身份假裝等安全問題,使用 HTTPS
通訊機制能夠有效地防止這些問題。 HTTP
的不足:瀏覽器
HTTP
的請求和響應數據。HTTP
協議中沒有加密機制,但經過 SSL
(Secure Socket Layer,安全套接層)或 TLS
(Transport Layer Security ,安全層傳輸協議)的組合使用,加密 HTTP
的通訊內容。 與 SSL
組合使用的 HTTP
被稱爲 HTTPS
(HTTP Secure,超文本傳輸安全協議)或 HTTP over SSL。安全
HTTPS = HTTP + 加密 + 認證 + 完整性保護服務器
HTTPS
並不是是應用層的一種新協議,只是 HTTP
通訊接口部分用 SSL
和 TLS
協議代替而已。一般 HTTP
直接跟 TCP
通訊,當使用 SSL
時,則變成先和 SSL
通訊,再由 SSL
和 TCP
通訊了。簡言之,HTTPS
就是身披 SSL
協議這層外殼的 HTTP
。 微信
咱們經常使用的加密方式有共享密鑰加密(對稱加密)和公開密鑰加密(非對稱加密)兩種。session
💡:在現代漢語裏,「鑰」讀yào的,只出如今【鑰匙】這個詞裏,「鑰」居詞首。其餘都讀yuè,且都出如今詞尾。app
加密和解密同用一個祕鑰的方式稱爲共享祕鑰加密
(Common key crypto system),也稱爲對稱祕鑰加密
。學習
💡:這個很好理解,舉個生活中常見的例子,你用鑰匙把錢放保險櫃裏了,把鑰匙給你媳婦了,你媳婦只有經過這把鑰匙才能打開保險櫃拿到錢。(鑰匙就是祕鑰,錢就是信息原文,裝了錢的保險櫃就是密文)網站
公開祕鑰加密很好地解決了共享祕鑰加密的困難。 它使用一堆非對稱的祕鑰,一把叫作私有密鑰(private key),另外一把公開密鑰(public key),顧名思義,私鑰不能讓其餘任何人知道,而公鑰則能夠隨意發佈。ui
使用公開祕鑰加密方式,發送密文的一方使用對方的公開密鑰進行加密,對方收到被加密的信息後再用本身的私鑰進行解密。這樣就不用發送私鑰了,也就不用擔憂被竊聽盜走私鑰。若是想僅僅根據密文和公鑰就恢復信息原文就目前的技術來看是不太現實的。
💡我想個例子幫助理解:騰訊發佈了微信 app,全部人均可下載註冊登陸,但只有騰訊有辦法查到你的密碼數據。別人就算拿了到你已經把微信登錄成功的手機,他在 app 裏也找不到你的密碼(用手機驗證重置密碼也得不到舊密碼數據)。這裏微信軟件註冊登陸功能就是
公鑰
,密碼數據就是信息原文
,登陸之後的微信就是密文
,騰訊查詢你密碼數據的能力就是祕鑰
。
SSL
採用的是公開密鑰加密(Public-key cryptography),屬於非對稱加密。HTTPS
採用混合加密機制,就是共享祕鑰加密和公開密鑰加密二者並用的混合加密機制。
爲何不全用公開密鑰加密?由於與共享祕鑰加密相比,處理起來更復雜、處理速度慢。因此 HTTPS
充分利用二者優點,在交換祕鑰環節使用公開密鑰加密方式,以後的簡歷通訊交換報文階段則用時共享祕鑰加密方式。
公開密鑰加密方式仍然有一些問題,那就是沒辦法證實公鑰自己是否是真的公鑰,有可能在公鑰傳輸中,真正的公鑰已經被攻擊者替換掉了。這時就須要使用數字證書認證機構(CA,Certificate Authority)和其相關機關頒發的公開密鑰證書。 數字證書認證機構的業務流程:
數字證書的生成是分層級的,下一級的證書須要其上一級證書的私鑰簽名。因此後者是前者的證書頒發者,也就是說上一級證書的主題名是其下一級證書的簽發者名。 例如打開咱們的 Safari 瀏覽器,在簡書的網站能夠看到網址前有一個🔐的標誌,點一下選擇顯示證書。 發現簡書的根證書是 DigiCert Global Root CA
:
二級證書是 DigiCert SHA2 Secure Server CA
:
最後的三級證書是 **.jianshu.com
:
Alamofire
請求的安全認證配置有這六種模式:
public enum ServerTrustPolicy {
case performDefaultEvaluation(validateHost: Bool)
case performRevokedEvaluation(validateHost: Bool, revocationFlags: CFOptionFlags)
case pinCertificates(certificates: [SecCertificate], validateCertificateChain: Bool, validateHost: Bool)
case pinPublicKeys(publicKeys: [SecKey], validateCertificateChain: Bool, validateHost: Bool)
case disableEvaluation
case customEvaluation((_ serverTrust: SecTrust, _ host: String) -> Bool)
複製代碼
.performDefaultEvaluation
默認策略,只有合法證書才能經過驗證.performRevokedEvaluation
對註銷證書作的一種額外設置.pinCertificates
證書驗證模式,表明客戶端會將服務器返回的證書和本地保存的證書中的 全部內容
所有進行校驗,若是正確,才繼續執行。.pinPublicKeys
公鑰驗證模式,表明客戶端會將服務器返回的證書和本地保存的證書中的 PublicKey部分
進行校驗,若是正確,才繼續執行。.disableEvaluation
該選項下驗證一直都是經過的,無條件信任。.customEvaluation
自定義驗證,須要返回一個布爾類型的結果。最經常使用的有這三種: .pinCertificates
證書驗證模式、.pinPublicKeys
公鑰驗證模式和 .disableEvaluation
不驗證模式
pinCertificates(certificates: [SecCertificate], validateCertificateChain: Bool, validateHost: Bool)
複製代碼
- 參數1:
certificates
表明的是證書- 參數2:
validateCertificateChain
表明是否驗證證書鏈- 參數3:
validateHost
表明是否驗證子地址
能夠看到 Alamofire
很是人性化,在 ServerTrustPolicy
枚舉中還給咱們提供了下面的方法,幫咱們遍歷查找出了項目主 bundle
中的證書:
public static func certificates(in bundle: Bundle = Bundle.main) -> [SecCertificate] {
var certificates: [SecCertificate] = []
let paths = Set([".cer", ".CER", ".crt", ".CRT", ".der", ".DER"].map { fileExtension in
bundle.paths(forResourcesOfType: fileExtension, inDirectory: nil)
}.joined())
for path in paths {
if
let certificateData = try? Data(contentsOf: URL(fileURLWithPath: path)) as CFData,
let certificate = SecCertificateCreateWithData(nil, certificateData)
{
certificates.append(certificate)
}
}
return certificates
}
複製代碼
certificates
傳參的時候直接傳 ServerTrustPolicy.certificates()
便可,若是你的證書是放在其餘 bundle
中,也能夠傳參進去指定 bundle
。
最後使用證書模式驗證完的整請求以下:
let serverTrustPlolicies:[String: ServerTrustPolicy] = [
hostUrl: .pinCertificates(
certificates: ServerTrustPolicy.certificates(),
validateCertificateChain: true,
validateHost: true)
]
let sessionManger = SessionManager(serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPlolicies))
sessionManager?.request(urlString).response { (defaultResponse) in
print(defaultResponse)
}
複製代碼
若是採用公鑰驗證模式,則使用 .pinPublicKeys
這個枚舉值,第一個參數傳公鑰,其餘參數和證書驗證模式同樣:
case pinPublicKeys(publicKeys: [SecKey], validateCertificateChain: Bool, validateHost: Bool)
複製代碼
第一個參數直接傳遞 Alamofire
提供給咱們的 ServerTrustPolicy.publicKeys()
方法便可。公鑰驗證模式的好處是,只要公鑰不變,就能夠一直使用,不用更新證書,不用擔憂證書過時了。
若是採用公鑰驗證模式,則使用 .disableEvaluation
,這樣就無論有沒有證書,證書有沒有效都採用非安全方式訪問了。
以上的總結參考了並部分摘抄瞭如下文章,很是感謝如下做者的分享!:
一、上野 宣 的《圖解https》
二、做者StanOz的《iOS 中對 HTTPS 證書鏈的驗證》
轉載請備註原文出處,不得用於商業傳播——凡幾多