在互聯網迅速發展的年代,基本上每天都在跟網絡打交道。那麼,在網絡的通信中怎麼保證信息的安全性呢?這篇文章,咱們就來說講,Alamofire
做爲iOS
開發中一個很是優秀的網絡請求相關的第三方庫,它的安全策略是怎麼設計和使用的。算法
在切入正題以前,先來簡單的瞭解一下HTTPS
相關知識,方便對後面內容的理解。若是你已經瞭解了,能夠直接跳過這一段。swift
在之前,咱們用的更多的是HTTP
,那麼是什麼緣由蘋果公司也主推咱們使用HTTPS
這個更安全請求方式的呢?HTTP
存在的問題:api
使用 HTTPS
通訊機制能夠有效地防止這些問題。HTTPS
並不是是應用層的一種新協議,只是HTTP
通訊接口部分用 SSL
和 TLS
協議代替而已。一般 HTTP
直接跟 TCP
通訊,當使用 SSL
時,則變成先和 SSL
通訊,再由 SSL
和 TCP
通訊了。簡言之,HTTPS
就是身披 SSL
協議這層外殼的 HTTP
。數組
HTTP+數據加密+身份認證+數據完整性保護=HTTPS安全
HTTPS
採用混合加密機制,就是共享祕鑰加密(對稱加密)和公開密鑰加密(非對稱加密)二者並用的混合加密機制。在交換密鑰環節使用公開密鑰加密的方式,以後創建通信交換報文階段則使用共享密鑰加密。公開密鑰加密比共享密鑰加密更加安全,那爲何不全用公開密鑰加密?由於與共享祕鑰加密相比,處理起來更復雜、處理速度慢。HTTPS
結合了兩種加密方式的優劣來實現一種混合加密的流程。如圖所示:服務器
HTTPS
有單向認證和雙向認證,原理基本差很少,這裏就講一下單向認證的整個流程,先看一張圖:網絡
HTTPS
請求:客戶端向服務端發送SSL
協議版本號、加密算法種類、隨機數等信息。HTTPS
協議的服務器必需要有一套數字證書,能夠本身製做,也能夠向組織申請。區別就是本身頒發的證書須要客戶端驗證經過,才能夠繼續訪問,而使用受信任的公司申請的證書能夠直接經過。這套證書其實就是一對公鑰和私鑰。SSL
協議版本號、加密算法種類、隨機數等信息TLS
來完成的,首先會驗證公鑰是否有效,好比頒發機構,過時時間等等,若是發現異常,則會拋出一個警告,提示證書存在問題。若是證書沒有問題,那麼就生成一個隨機值,而後用證書對該隨機值進行加密。若是使用的是自簽證書須要咱們進行安全認證,若是是CA機構頒發的證書是不須要咱們寫安全認證的相關代碼的。 舉個Alamofire
發起HTTPS
請求的栗子🌰:session
let serverTrustPlolicies: [String: ServerTrustPolicy] = [
hostUrl: .pinCertificates(
certificates: ServerTrustPolicy.certificates(),
validateCertificateChain: true,
validateHost: true)
]
self.sessionManager = SessionManager(serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPlolicies))
self.sessionManager?.request(urlString).response { (defaultResponse) in
print(defaultResponse)
}
複製代碼
HTTP
相比,只是在初始化SessionManager
的時候傳入了一個ServerTrustPolicyManager
對象,它是證書信任策略的管理者。ServerTrustPolicyManager
對象的時候,傳入了一個[String: ServerTrustPolicy]
類型的集合做爲參數並保存,key
是主機地址,value
是驗證模式。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)
}
複製代碼
Alamofire
安全認證策略的六種模式,其中最經常使用的有這三種:.pinCertificates
證書驗證模式、.pinPublicKeys
公鑰驗證模式和 .disableEvaluation
不驗證模式。
.performDefaultEvaluation
默認策略,只有合法證書才能經過驗證.performRevokedEvaluation
對註銷證書作的一種額外設置.pinCertificates
證書驗證模式,表明客戶端會將服務器返回的證書和本地保存的證書中的 全部內容 所有進行校驗,若是正確,才繼續執行。.pinPublicKeys
公鑰驗證模式,表明客戶端會將服務器返回的證書和本地保存的證書中的 PublicKey部分 進行校驗,若是正確,才繼續執行。.disableEvaluation
該選項下驗證一直都是經過的,無條件信任。.customEvaluation
自定義驗證,須要返回一個布爾類型的結果。.pinCertificates
證書驗證模式。它有三個關聯值:
certificates
表明的是證書validateCertificateChain
表明是否驗證證書鏈validateHost
表明是否驗證子地址Alamofire
爲咱們提供了一個方法ServerTrustPolicy.certificates()
方便使用。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
}
複製代碼
Bundle.main
中查找,咱們也能夠指定存放證書的Bundle
來查找。URLSessionTaskDelegate
的下面這個方法。open func urlSession( _ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)
{
guard taskDidReceiveChallengeWithCompletion == nil else {
taskDidReceiveChallengeWithCompletion?(session, task, challenge, completionHandler)
return
}
if let taskDidReceiveChallenge = taskDidReceiveChallenge {
let result = taskDidReceiveChallenge(session, task, challenge)
completionHandler(result.0, result.1)
} else if let delegate = self[task]?.delegate {
delegate.urlSession(
session,
task: task,
didReceive: challenge,
completionHandler: completionHandler
)
} else {
urlSession(session, didReceive: challenge, completionHandler: completionHandler)
}
}
複製代碼
若是taskDidReceiveChallengeWithCompletion
有值的話,直接回調這個閉包,這就說明咱們能夠本身實現驗證的邏輯。可見Alamofire
是很是的友好的,既提供了常規實現方式,也支持開發者自定義實現。閉包
繼續跟蹤代碼進入到delegate.urlSession
方法裏面app
而後會執行紅框所示的方法,獲取的是前面設置的驗證模式,而後執行evaluate
方法
public func evaluate(_ serverTrust: SecTrust, forHost host: String) -> Bool {
var serverTrustIsValid = false
switch self {
// 省略沒法代碼.....
case let .pinCertificates(pinnedCertificates, validateCertificateChain, validateHost):
if validateCertificateChain {
let policy = SecPolicyCreateSSL(true, validateHost ? host as CFString : nil)
SecTrustSetPolicies(serverTrust, policy)
SecTrustSetAnchorCertificates(serverTrust, pinnedCertificates as CFArray)
SecTrustSetAnchorCertificatesOnly(serverTrust, true)
serverTrustIsValid = trustIsValid(serverTrust)
} else {
let serverCertificatesDataArray = certificateData(for: serverTrust)
let pinnedCertificatesDataArray = certificateData(for: pinnedCertificates)
outerLoop: for serverCertificateData in serverCertificatesDataArray {
for pinnedCertificateData in pinnedCertificatesDataArray {
if serverCertificateData == pinnedCertificateData {
serverTrustIsValid = true
break outerLoop
}
}
}
}
// 省略沒法代碼.....
return serverTrustIsValid
}
複製代碼
if
代碼塊,大概步驟以下:
SecPolicyCreateSSL
:建立策略,是否驗證hostSecTrustSetPolicies
:爲待驗證的對象設置策略trustIsValid
:進行驗證,成功返回YES
.pinPublicKeys
這個枚舉值,第一個參數傳公鑰,其餘參數和證書驗證模式同樣。Alamofire
一樣爲咱們提供了獲取公鑰的方法ServerTrustPolicy.publicKeys()
,直接調用這個方法便可。這篇文章大概聊了一下HTTPS
的加密流程,以及經過如何Alamofire
請求HTTPS
的接口和網絡挑戰流程的分析。固然,若是想完全明白HTTPS
的實現方式,還需繼續學習。推薦一本書《圖解HTTP》,講的很是通俗易懂,文章的幾張圖片也是來源於這本書。
有問題或者建議和意見,歡迎你們評論或者私信。 喜歡的朋友能夠點下關注和喜歡,後續會持續更新文章。