Alamofire 學習--安全認證

1、HTTPS

在學習 Alamofire 的安全認證以前,咱們先來了解下 HTTPSswift

一、爲何要用 HTTPS

HTTP 協議中有可能存在信息竊聽或者身份假裝等安全問題,使用 HTTPS 通訊機制能夠有效地防止這些問題。 HTTP 的不足:瀏覽器

  • 通訊使用明文(不加密),內容可能會被竊聽。
  • 不驗證通訊方的身份,所以有可能遭遇假裝
  • 我發證實報文的完整性,因此有可能已遭篡改 像咱們平時經常使用的抓包軟件 Wireshark、Charles 等均可以輕鬆抓取到 HTTP 的請求和響應數據。

HTTP 協議中沒有加密機制,但經過 SSLSecure Socket Layer,安全套接層)或 TLSTransport Layer Security ,安全層傳輸協議)的組合使用,加密 HTTP 的通訊內容。 與 SSL 組合使用的 HTTP 被稱爲 HTTPSHTTP Secure,超文本傳輸安全協議)或 HTTP over SSL安全

HTTPS = HTTP + 加密 + 認證 + 完整性保護服務器

HTTPS 並不是是應用層的一種新協議,只是 HTTP 通訊接口部分用 SSLTLS 協議代替而已。一般 HTTP 直接跟 TCP 通訊,當使用 SSL 時,則變成先和 SSL 通訊,再由 SSLTCP 通訊了。簡言之,HTTPS 就是身披 SSL 協議這層外殼的 HTTP微信

二、加密技術

咱們經常使用的加密方式有共享密鑰加密(對稱加密)和公開密鑰加密(非對稱加密)兩種。session

💡:在現代漢語裏,「鑰」讀yào的,只出如今【鑰匙】這個詞裏,「鑰」居詞首。其餘都讀yuè,且都出如今詞尾。app

一、共享祕鑰加密

加密和解密同用一個祕鑰的方式稱爲共享祕鑰加密Common key crypto system),也稱爲對稱祕鑰加密學習

💡:這個很好理解,舉個生活中常見的例子,你用鑰匙把錢放保險櫃裏了,把鑰匙給你媳婦了,你媳婦只有經過這把鑰匙才能打開保險櫃拿到錢。(鑰匙就是祕鑰,錢就是信息原文,裝了錢的保險櫃就是密文)網站

  • 祕鑰發送問題: 以共享祕鑰方式加密時必須將祕鑰也發給對方,但在互聯網上轉發祕鑰時就有被竊聽的風險,不發送對方就不能解密,若是祕鑰都安全送達了,那數據也應該能安全送達了。另外還得設法安全的保管接收到的祕鑰。

二、公開祕鑰加密

公開祕鑰加密很好地解決了共享祕鑰加密的困難。 它使用一堆非對稱的祕鑰,一把叫作私有密鑰(private key),另外一把公開密鑰(public key),顧名思義,私鑰不能讓其餘任何人知道,而公鑰則能夠隨意發佈。ui

使用公開祕鑰加密方式,發送密文的一方使用對方的公開密鑰進行加密,對方收到被加密的信息後再用本身的私鑰進行解密。這樣就不用發送私鑰了,也就不用擔憂被竊聽盜走私鑰。若是想僅僅根據密文和公鑰就恢復信息原文就目前的技術來看是不太現實的。

💡我想個例子幫助理解:騰訊發佈了微信 app,全部人均可下載註冊登陸,但只有騰訊有辦法查到你的密碼數據。別人就算拿了到你已經把微信登錄成功的手機,他在 app 裏也找不到你的密碼(用手機驗證重置密碼也得不到舊密碼數據)。這裏微信軟件註冊登陸功能就是公鑰,密碼數據就是信息原文,登陸之後的微信就是密文,騰訊查詢你密碼數據的能力就是祕鑰

三、HTTPS 混合加密機制

SSL 採用的是公開密鑰加密(Public-key cryptography),屬於非對稱加密。HTTPS 採用混合加密機制,就是共享祕鑰加密和公開密鑰加密二者並用的混合加密機制。

爲何不全用公開密鑰加密?由於與共享祕鑰加密相比,處理起來更復雜、處理速度慢。因此 HTTPS 充分利用二者優點,在交換祕鑰環節使用公開密鑰加密方式,以後的簡歷通訊交換報文階段則用時共享祕鑰加密方式。

三、證實公鑰正確性的證書

公開密鑰加密方式仍然有一些問題,那就是沒辦法證實公鑰自己是否是真的公鑰,有可能在公鑰傳輸中,真正的公鑰已經被攻擊者替換掉了。這時就須要使用數字證書認證機構(CA,Certificate Authority)和其相關機關頒發的公開密鑰證書。 數字證書認證機構的業務流程:

數字證書的生成是分層級的,下一級的證書須要其上一級證書的私鑰簽名。因此後者是前者的證書頒發者,也就是說上一級證書的主題名是其下一級證書的簽發者名。 例如打開咱們的 Safari 瀏覽器,在簡書的網站能夠看到網址前有一個🔐的標誌,點一下選擇顯示證書。 發現簡書的根證書是 DigiCert Global Root CA

二級證書是 DigiCert SHA2 Secure Server CA

最後的三級證書是 **.jianshu.com

2、Alamofire 中的安全認證

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 證書鏈的驗證》

轉載請備註原文出處,不得用於商業傳播——凡幾多

相關文章
相關標籤/搜索