web-dev-qa-db-ja.com

SwiftおよびNSURLSessionを使用したiOS証明書の固定

証明書のピン留めをSwiftのNSURLSessionに追加する方法

OWASP Webサイト には、Objective-CおよびNSURLConnectionの例のみが含まれています。

12
lifeisfoo

準備が整いましたが、SecTrustEvaluateは非推奨であり、SecTrustEvaluateWithErrorに置き換える必要があります。

だからこれ:

var secresult = SecTrustResultType.invalid
let status = SecTrustEvaluate(serverTrust, &secresult)

if errSecSuccess == status {
   // Proceed with evaluation
   switch result {
   case .unspecified, .proceed:    return true
   default:                        return false
   }
}

私が書いた理由// Proceed with evaluationセクションは、secresultを検証する必要があるためです。これは、証明書が実際に無効であることを示している可能性もあります。これを上書きし、発生した問題を例外として追加するオプションがあります。できれば、ユーザーに決定を求めた後です。

これである必要があります:

if SecTrustEvaluateWithError(server, nil) {
   // Certificate is valid, proceed.
}

2番目のパラメーターはエラーをキャプチャしますが、詳細に関心がない場合は、nilを渡すだけです。

1
thecivillain

これを試すことができます。

import Foundation
import Security

class NSURLSessionPinningDelegate: NSObject, URLSessionDelegate {

      let certFileName = "name-of-cert-file"
      let certFileType = "cer"

      func urlSession(_ session: URLSession, 
                  didReceive challenge: URLAuthenticationChallenge, 
                  completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void) {

    if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) {
        if let serverTrust = challenge.protectionSpace.serverTrust {
            var secresult = SecTrustResultType.invalid
            let status = SecTrustEvaluate(serverTrust, &secresult)

            if(errSecSuccess == status) {
                if let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0) {
                    let serverCertificateData = SecCertificateCopyData(serverCertificate)
                    let data = CFDataGetBytePtr(serverCertificateData);
                    let size = CFDataGetLength(serverCertificateData);
                    let certificateOne = NSData(bytes: data, length: size)
                    let filePath = Bundle.main.path(forResource: self.certFileName, 
                                                         ofType: self.certFileType)

                    if let file = filePath {
                        if let certificateTwo = NSData(contentsOfFile: file) {
                            if certificateOne.isEqual(to: certificateTwo as Data) {
                                completionHandler(URLSession.AuthChallengeDisposition.useCredential, 
                                                  URLCredential(trust:serverTrust))
                                return
                            }
                        }
                    }
                }
            }
        }
    }

    // Pinning failed
    completionHandler(URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
}
}

ソース: https://www.steveclarkapps.com/using-certificate-pinning-xcode/

0