Browse Questions
Answer: SSL pinning validates that the server's certificate matches a known copy embedded in the app, preventing man-in-the-middle attacks even with valid certificates.
Code Example:
class PinnedSessionDelegate: NSObject, URLSessionDelegate {
func urlSession(_ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,
let serverTrust = challenge.protectionSpace.serverTrust else {
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
// Load pinned certificate from bundle
guard let certPath = Bundle.main.path(forResource: "api_cert", ofType: "cer"),
let pinnedData = NSData(contentsOfFile: certPath),
let serverCert = SecTrustGetCertificateAtIndex(serverTrust, 0) else {
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
let serverData = SecCertificateCopyData(serverCert) as NSData
if serverData.isEqual(to: pinnedData as Data) {
completionHandler(.useCredential, URLCredential(trust: serverTrust))
} else {
completionHandler(.cancelAuthenticationChallenge, nil)
}
}
}
let session = URLSession(configuration: .default,
delegate: PinnedSessionDelegate(),
delegateQueue: nil)