什麼是 SSL Pinning?

一種加強 App 和 Server 間通訊安全性的方法。主要目標是確保 App 僅與預先驗證的 Server 建立安全連接,防止中間人攻擊(Man-in-the-Middle,MitM)等安全風險。一般會有兩種方式進行驗證,Certificate PinningPublic Key Pinning

Certificate Pinning

Certificate Pinning 通常需要驗證整張 SSL 證書,因此安全性相對較高。然而,此方法較為固定,如果 Server 更新證書,App 需要定期更新並重新上架。

首先,我們可以建立一個 Certificates 結構,用於從 App 內取得憑證檔案。

struct Certificates {
    static let testSSLPinning = Certificates.certificate(filename: "testSSLPinning")
    
    private static func certificate(filename: String, type: String = "cer") -> SecCertificate {
        let filePath = Bundle.main.path(forResource: filename, ofType: type)!
        let data = try! Data(contentsOf: URL(fileURLWithPath: filePath))
        let certificate = SecCertificateCreateWithData(nil, data as CFData)!
        return certificate
    }
}

建立自定義的Session

let CertificateSessionManager: Session = {
    let configuration = URLSessionConfiguration.af.default
    configuration.urlCache = nil
   
		let interceptor = SPNetworkInterceptor()
    
    let testSSLPinningDomain = "www.github.com"
    
		// key 是要進行 SSLPinning 的 domain
		// value 則是一個 PinnedCertificatesTrustEvaluator,將前面所定義的憑證檔進行驗證
    let evaluators: [String: ServerTrustEvaluating] = [
        testSSLPinningDomain: PinnedCertificatesTrustEvaluator(certificates: [Certificates.testSSLPinning]))
    ]
		
    let serverTrustManager = ServerTrustManager(allHostsMustBeEvaluated: false, evaluators: evaluators)
    
		let session = Session(configuration: configuration,
                          interceptor: interceptor,
                          serverTrustManager: serverTrustManager,
                          cachedResponseHandler: ResponseCacher(behavior: .doNotCache))
    
    return session
}()

Public key Pinning

Public Key Pinning 則僅驗證公開金鑰,不需驗證整張憑證。這使得當憑證需要更新時,只需確保公鑰保持不變,無需經常更新 App。

利用 檢測網站 SSL 憑證安全等級 這個網站取得公鑰 SHA256

截圖 2023-08-31 上午12.41.56.png

導入 https://github.com/datatheorem/TrustKit

pod 'TrustKit'