如何在Swift中将证书固定到NSURLSession?
该OWASP网站只包含Objective- C和NSURLConnection的一个例子。
Swift 3+ 更新:
只需定义一个委托类NSURLSessionDelegate并实现didReceiveChallenge函数( 此代码改编自Objective-c OWASP示例 ):
NSURLSessionDelegate
class NSURLSessionPinningDelegate: NSObject, URLSessionDelegate { func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void) { // Adapted from OWASP https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#iOS if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) { if let serverTrust = challenge.protectionSpace.serverTrust { let isServerTrusted = SecTrustEvaluateWithError(serverTrust, nil) if(isServerTrusted) { if let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0) { let serverCertificateData = SecCertificateCopyData(serverCertificate) let data = CFDataGetBytePtr(serverCertificateData); let size = CFDataGetLength(serverCertificateData); let cert1 = NSData(bytes: data, length: size) let file_der = Bundle.main.path(forResource: "certificateFile", ofType: "der") if let file = file_der { if let cert2 = NSData(contentsOfFile: file) { if cert1.isEqual(to: cert2 as Data) { completionHandler(URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust:serverTrust)) return } } } } } } } // Pinning failed completionHandler(URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil) } }
(您可以在此处找到Swift 2的Gist- 从初始答案开始)
然后使用创建.der网站的文件openssl
.der
openssl
openssl s_client -connect my-https-website.com:443 -showcerts < /dev/null | openssl x509 -outform DER > my-https-website.der
并将其添加到xcode项目。仔细检查列表中的Build phases标签中是否存在该标签Copy Bundle Resources。否则,将其拖放到此列表中。
Build phases
Copy Bundle Resources
最后在代码中使用它来发出URL请求:
if let url = NSURL(string: "https://my-https-website.com") { let session = URLSession( configuration: URLSessionConfiguration.ephemeral, delegate: NSURLSessionPinningDelegate(), delegateQueue: nil) let task = session.dataTask(with: url as URL, completionHandler: { (data, response, error) -> Void in if error != nil { print("error: \(error!.localizedDescription): \(error!)") } else if data != nil { if let str = NSString(data: data!, encoding: String.Encoding.utf8.rawValue) { print("Received data:\n\(str)") } else { print("Unable to convert data to text") } } }) task.resume() } else { print("Unable to create NSURL") }