HTTPS握手
先說聲https握手,傳送 HTTPS 請求首先要進行 SSL/TLS 握手,握手過程大致如下:
1.客戶端發起握手請求,攜帶隨機數、支援演算法列表等引數。 2.服務端收到請求,選擇合適的演算法,下發公鑰證書和隨機數。 3.客戶端對服務端證書進行校驗,併傳送隨機數資訊,該資訊使用公鑰加密。 4.服務端通過私鑰獲取隨機數資訊。 5.雙方根據以上互動的資訊生成session ticket,用作該連線後續資料傳輸的加密金鑰。 上述過程中,和“IP直連”有關的是第3步,客戶端需要驗證服務端下發的證書,驗證過程有以下兩個要點:
1.客戶端用本地儲存的根證書解開證書鏈,確認服務端下發的證書是由可信任的機構頒發的。 2.客戶端需要檢查證書的 domain 域和擴充套件域,看是否包含本次請求的 host。 如果上述兩點都校驗通過,就證明當前的服務端是可信任的,否則就是不可信任,應當中斷當前連線。
當客戶端使用“IP直連”解析域名時,請求URL中的host會被替換成解析出來的IP,所以在證書驗證的第2步,會出現domain不匹配的情況,導致SSL/TLS握手不成功。
問題的產生:
平時的swift專案開發過程中,我們需要在測試服進行開發以及測試,當網路環境配置成https的時候,經常需要載入網路請求,或者展示網路圖片,測試服都是自建證書,預設情況下Moya,和KingFisher不會通過驗證,導致網路(圖片)載入不同。
複製程式碼
解決方法:
關閉Https的證書認證 驗證自簽名證書,CN 是否合法
Moya
方法一:
/// 關閉https認證
let serverTrustPolicies: [String: ServerTrustPolicy] = [
“172.16.88.106”: .disableEvaluation
]
let manager = Manager(
configuration: URLSessionConfiguration.default,
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
)
let provider = MoyaProvider(manager: manager, plugins: [NetworkLoggerPlugin(verbose: true)])
方法一是一種變通實現的方法,它直接關閉了Https的Domain驗證,雖然可以請求正常進行,但是如果在客戶端和伺服器之間增加代理,請求傳送時代理替換證書,那麼代理就可以輕易拿到請求的資料,出於安全考慮並不推薦這種做法。
方法二:
ServerTrustPolicy列舉中使用pinCertificates。
case pinCertificates(certificates: [SecCertificate], validateCertificateChain: Bool, validateHost: Bool)
傳入自簽名證書資訊。
示例程式碼:
let path = Bundle.main .path(forResource: "selfSigned_pubCA.cer", ofType: nil)
let data = NSData(contentsOfFile: path!)
let certificates :[SecCertificate] = [data as! SecCertificate]
let policies : [String : ServerTrustPolicy] = ["172.16.88.230" : .pinCertificates(certificates: certificates, validateCertificateChain: true, validateHost: true)]
把這個 policies 作為引數傳進manager 建構函式中即可
複製程式碼
KingFisher信任Host方法
A lightweight, pure-Swift library for downloading and caching images from the web. github.com/onevcat/Kin…
//取出downloader單例
let downloader = KingfisherManager.shared.downloader
//信任ip為106的
Serverdownloader.trustedHosts = Set(["172.16.88.106"])
//使用KingFisher給ImageView賦網路圖片
iconView.kf.setImage(with: iconUrl)
複製程式碼