自签名证书的Swift SSL错误

此代码尝试访问并且无法访问在浏览器中工作的SSL URL:

let path = "https://localhost:8443/greeting" let request = NSMutableURLRequest(URL: NSURL(string: path)!) let session = NSURLSession.sharedSession() let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in let json:JSON = JSON(data: data!) if let c = json["content"].string { print(c) } }) task.resume() 

失败并出现错误:

可选(错误域= NSURLErrorDomain代码= -1200“发生SSL错误,无法建立与服务器的安全连接。”UserInfo = {NSURLErrorFailingURLPeerTrustErrorKey =,

允许应用程序接受此证书需要什么?

有问题的证书是自签名的。 在SO上阅读一些解决方案但没有成功。

运行Xcode 7.2

@Ashish Kakkad是当场的。 这有效:

 class Blah: NSURLSessionDelegate { func rest() { let path = "https://localhost:8443/greeting" let request = NSMutableURLRequest(URL: NSURL(string: path)!) let configuration = NSURLSessionConfiguration.defaultSessionConfiguration() let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue:NSOperationQueue.mainQueue()) let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in let json:JSON = JSON(data: data!) if let c = json["content"].string { print(c) } }) task.resume() } func URLSession(session: NSURLSession, task: NSURLSessionTask, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) { completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!)) } 

在Info.plist文件中使用它:

 NSAppTransportSecurity  NSExceptionDomains  localhost  NSExceptionAllowsInsecureHTTPLoads     

您可以使用自己的证书而不是我的证书(fullchain.pem)

  class AccessingServer: NSObject,URLSessionDelegate { func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust { // First load our extra root-CAs to be trusted from the app bundle. let trust = challenge.protectionSpace.serverTrust let rootCa = "fullchain" if let rootCaPath = Bundle.main.path(forResource: rootCa, ofType: "pem") { if let rootCaData = NSData(contentsOfFile: rootCaPath) { let rootCert = SecCertificateCreateWithData(nil, rootCaData) // let certArrayRef = CFArrayCreate(nil, UnsafeMutablePointer>([rootCert]), 1, nil) SecTrustSetAnchorCertificates(trust!, rootCert as! CFArray) SecTrustSetAnchorCertificatesOnly(trust!, false) } } var trustResult: SecTrustResultType = SecTrustResultType.invalid SecTrustEvaluate(trust!, &trustResult) if (trustResult == SecTrustResultType.unspecified || trustResult == SecTrustResultType.proceed) { // Trust certificate. let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!) challenge.sender?.use(credential, for: challenge) } else { NSLog("Invalid server certificate.") challenge.sender?.cancel(challenge) } } else { NSLog("Got unexpected authentication method \(challenge.protectionSpace.authenticationMethod)"); challenge.sender?.cancel(challenge) } } } 

Sai Reddy的解决方案允许您接受自签名证书,如果它有完整的链,但它也接受其他人。

Marcus Leon的解决方案是完全覆盖 – 基本上忽略了所有证书。

我更喜欢这个。

Swift 4.1,iOS 11.4.1

首先,在您的Info.plist中:

 NSAppTransportSecurity  NSAllowsArbitraryLoads   

其次,无论你在哪里使用NSURLSession,而不是使用URLSession.shared进行设置,请使用以下内容:

 session = URLSession(configuration: .default, delegate: APIURLSessionTaskDelegate(isSSLPinningEnabled: isSSLPinningEnabled), delegateQueue: nil) 

然后添加此类以处理固定:

  func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { print("*** received SESSION challenge...\(challenge)") let trust = challenge.protectionSpace.serverTrust! let credential = URLCredential(trust: trust) guard isSSLPinningEnabled else { print("*** SSL Pinning Disabled -- Using default handling.") completionHandler(.useCredential, credential) return } let myCertName = "my_certificate_to_pin" var remoteCertMatchesPinnedCert = false if let myCertPath = Bundle.main.path(forResource: myCertName, ofType: "der") { if let pinnedCertData = NSData(contentsOfFile: myCertPath) { // Compare certificate data let remoteCertData: NSData = SecCertificateCopyData(SecTrustGetCertificateAtIndex(trust, 0)!) if remoteCertData.isEqual(to: pinnedCertData as Data) { print("*** CERTIFICATE DATA MATCHES") remoteCertMatchesPinnedCert = true } else { print("*** MISMATCH IN CERT DATA.... :(") } } else { print("*** Couldn't read pinning certificate data") } } else { print("*** Couldn't load pinning certificate!") } if remoteCertMatchesPinnedCert { print("*** TRUSTING CERTIFICATE") completionHandler(.useCredential, credential) } else { print("NOT TRUSTING CERTIFICATE") completionHandler(.rejectProtectionSpace, nil) } } } 

此类检查您是否启用了证书固定。 如果您这样做,它将完全忽略正常的证书validation,并与我们在应用程序中包含的证书进行精确比较。 通过这种方式, 它只接受您的自签名证书,而不接受任何其他证书。

此解决方案要求您在项目的Resources文件夹中放置“ my_certificate_to_pin.der ”文件。 如果您还没有Resources文件夹,只需添加一个。

该证书应为DER格式。

要为服务器创建自签名证书,通常会执行以下操作:

 openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout mycert.key -out mycert.cer 

这会生成两个文件 – 一个mycert.key私钥文件和一个mycert.cer – 证书本身。 这些都是X509格式。 对于iOS,您将需要DER格式的证书,所以这样做:

 openssl x509 -outform der -in mycert.cer -out my_certificate_to_pin.der 

这会在iOS上生成您需要的文件。