1

我刚刚转移到 Alamofire 5。

早些时候,我使用 URLSession 和Certificate Pinner来处理身份验证挑战,我使用了URLSessionDelegate带哈希值的委托方法

func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge,
                completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
    print("being challanged! for \(challenge.protectionSpace.host)")
    guard let trust = challenge.protectionSpace.serverTrust else {
        print("invalid trust!")
        completionHandler(.cancelAuthenticationChallenge, nil)
        return
    }

    let credential = URLCredential(trust: trust)

    let pinner = setupCertificatePinner(host: challenge.protectionSpace.host)

    if (!pinner.validateCertificateTrustChain(trust)) {
        print("failed: invalid certificate chain!")
        challenge.sender?.cancel(challenge)
    }

    if (pinner.validateTrustPublicKeys(trust)) {
        completionHandler(.useCredential, credential)
    } else {
        didPinningFailed = true
        print("couldn't validate trust for \(challenge.protectionSpace.host)")
        completionHandler(.cancelAuthenticationChallenge, nil)
    }

}

迁移到 Alamofire 5 后,没有sessionDidReceiveChallenge早期版本中可用的方法。

我试过了:

private let session: Session = {
    let manager = ServerTrustManager(allHostsMustBeEvaluated: true, evaluators:
        ["devDomain.com": DisabledTrustEvaluator(),
         "prodDomain.com": PublicKeysTrustEvaluator()])
    let configuration = URLSessionConfiguration.af.default

    return Session(configuration: configuration, serverTrustManager: manager)
}()

但我得到错误:

Error Domain=Alamofire.AFError Code=11 "Server trust evaluation failed due to reason: No public keys were found or provided for evaluation."

更新: 我仍然更喜欢仅使用 256 指纹解析它的方法,因为我们在第一次 api 调用中获得域及其哈希值。

4

2 回答 2

1

首先,您需要一个ServerTrustEvaluating处理证书的简单工具,类似于

public final class CertificatePinnerTrustEvaluator: ServerTrustEvaluating {

    public init() {}

    func setupCertificatePinner(host: String) -> CertificatePinner {

        //get the CertificatePinner
    }

    public func evaluate(_ trust: SecTrust, forHost host: String) throws {

        let pinner = setupCertificatePinner(host: host)

        if (!pinner.validateCertificateTrustChain(trust)) {
            print("failed: invalid certificate chain!")
            throw AFError.serverTrustEvaluationFailed(reason: .noCertificatesFound)
        }

        if (!pinner.validateTrustPublicKeys(trust)) {
            print ("couldn't validate trust for \(host)")

            throw AFError.serverTrustEvaluationFailed(reason: .noCertificatesFound)
        }
    }
}

为了能够使用相同的评估器,我建议子类ServerTrustManager化以返回相同的评估器,我这样做是这样的:

class CertificatePinnerServerTrustManager: ServerTrustManager {

    let evaluator = CertificatePinnerTrustEvaluator()

    init() {
        super.init(allHostsMustBeEvaluated: true, evaluators: [:])
    }

    open override func serverTrustEvaluator(forHost host: String) throws -> ServerTrustEvaluating? {

        return evaluator
    }
}

之后,您应该准备好创建会话并将管理器传递给它

private let session: Session = {

    let trustManager = CertificatePinnerServerTrustManager()

    return Session(serverTrustManager: trustManager)
}()

我的参考是第urlSession(_:task:didReceive:completionHandler:)86 行的 SessionDelegate.swift 中 Alamofire 源代码中的方法(Alamofire V5.2.1)

于 2020-06-08T07:41:49.660 回答
0

如果您想使用公钥固定,您需要提供证书以解析应用程序包中的这些公钥,或者以其他方式将它们提供给PublicKeysTrustEvaluator.

于 2020-06-04T21:52:50.117 回答