自签名证书的Swift SSL错误

Mar*_*eon 9 ssl xcode ios swift

此代码尝试访问并且无法访问在浏览器中工作的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()
Run Code Online (Sandbox Code Playgroud)

失败并出现错误:

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

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

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

运行Xcode 7.2

Mar*_*eon 15

@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!))
}
Run Code Online (Sandbox Code Playgroud)

在Info.plist文件中使用它:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>localhost</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
    </dict>
</dict>
Run Code Online (Sandbox Code Playgroud)

  • 这有效,但只是一种解决方法.另请注意,很快就会弃用ATS的例外情况. (2认同)
  • 此解决方案只是完全忽略证书,而不是尝试确认用户正在使用自签名证书。 (2认同)

dre*_*ter 9

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

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

我更喜欢这个.

Swift 4.1,iOS 11.4.1

首先,在您的Info.plist中:

<key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>
Run Code Online (Sandbox Code Playgroud)

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

session = URLSession(configuration: .default, delegate: APIURLSessionTaskDelegate(isSSLPinningEnabled: isSSLPinningEnabled), delegateQueue: nil)
Run Code Online (Sandbox Code Playgroud)

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

    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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

该证书应为DER格式.

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

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout mycert.key -out mycert.cer
Run Code Online (Sandbox Code Playgroud)

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

openssl x509 -outform der -in mycert.cer -out my_certificate_to_pin.der
Run Code Online (Sandbox Code Playgroud)

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


归档时间:

查看次数:

28115 次

最近记录:

5 年,11 月 前