web-dev-qa-db-ja.com

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を実行する

9
Marcus Leon

@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ファイルでこれを使用すると:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>localhost</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
    </dict>
</dict>
15
Marcus Leon

Sai Reddyのソリューションでは、完全なチェーンがある場合、自己署名証明書を受け入れることができますが、他の証明書も受け入れます。

マーカスレオンのソリューションは、完全なオーバーライドであり、基本的にすべての証明書を無視します。

私はこれがもっと好きです。

Swift 4.1、iOS 11.4.1

まず、Info.plistで:

<key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>

次に、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)
        }
    }
}

このクラスは、証明書のピン留めを有効にしたかどうかを確認します。行った場合、通常の証明書の検証は完全に無視され、アプリに含まれる証明書と正確に比較されます。このようにして、onlyは自己署名証明書を受け入れ、それ以外は受け入れません。

このソリューションでは、プロジェクトの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-証明書自体の2つのファイルが生成されます。これらは両方ともX509形式です。 iOSの場合、DER形式の証明書が必要になるため、次のようにします。

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

これにより、iOSで必要なファイルが生成されます。

9
drewster

私の証明書(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<UnsafePointer<Any>>([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)
        }
    }

   }
3
Sai kumar Reddy