Кто-нибудь видел способ сделать пиннинг с Alamofire по отпечатку пальца вместо открытого ключа?

Извините, если на это был дан ответ, но я его нигде не видел.

Благодарность

4
Bob 10 Май 2016 в 06:34

3 ответа

Лучший ответ

В итоге все оказалось довольно просто. Приведенный ниже код может быть не идеальным, мой реальный код выполняет некоторые дополнительные проверки, но это большая часть.

.SHA1Fingerprint - это метод расширения в SecCertificate, который копирует его в NSData, а затем преобразует в SHA1. Для этого я использую RNCryptor, но вы можете это сделать.

IsValidFingerprint просто сравнивает результат с каждым из моих известных отпечатков пальцев.

Все это зависает от моего статического Alamofire.Manager.

manager.delegate.sessionDidReceiveChallenge = { session, challenge in
        var disposition: NSURLSessionAuthChallengeDisposition = .PerformDefaultHandling
        var credential: NSURLCredential?

        if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
            let host = challenge.protectionSpace.host

            if let serverTrust = challenge.protectionSpace.serverTrust {

                let serverTrustPolicy = ServerTrustPolicy.PerformDefaultEvaluation(validateHost: true)

                if serverTrustPolicy.evaluateServerTrust(serverTrust, isValidForHost: host) {
                    disposition = .UseCredential
                    credential = NSURLCredential(forTrust: serverTrust)
                } else {
                    disposition = .CancelAuthenticationChallenge
                    return (disposition, credential)
                }

                for index in 0..<SecTrustGetCertificateCount(serverTrust) {
                    if let certificate = SecTrustGetCertificateAtIndex(serverTrust, index) {
                        if let fingerPrint = certificate.SHA1Fingerprint {
                            if isValidFingerprint(fingerPrint)  {
                                return (disposition, credential)
                            }
                        }
                    }
                }
            }
        }
        disposition = .CancelAuthenticationChallenge
        return (disposition, credential)
    }
3
Bob 15 Май 2016 в 05:49

Swift 4

Я изменил ответ Боба, и он сработал для меня, вы можете изменить свой алгоритм проверки в соответствии с вашими требованиями, этот код просто проверяет, является ли один из закрепленных сертификатов действительным или нет. эта ссылка помогла мне понять мою проблему

private static var Manager : Alamofire.SessionManager = {
    let man = Alamofire.SessionManager()
    man.delegate.sessionDidReceiveChallenge = { session, challenge in
        var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling
        var credential: URLCredential?
        if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
            let host = challenge.protectionSpace.host

            if let serverTrust = challenge.protectionSpace.serverTrust {

                let serverTrustPolicy = ServerTrustPolicy.performDefaultEvaluation(validateHost: true)
                if serverTrustPolicy.evaluate(serverTrust, forHost: host) {
                    disposition = .useCredential
                    credential = URLCredential(trust: serverTrust)
                } else {
                    disposition = .cancelAuthenticationChallenge
                    return (disposition, credential)
                }
                let fingerPrints = [
                    "AJKSFGSGFR64563RFGY874FG43G784F48FG4F4GF74GF4F7G4FGF4F74F7GFF58Y".lowercased(),
                    "BJKSFGSGFR64563RFGY874FG43G784F48FG4F4GF74GF4F7G4FGF4F74F7GFF58Y".lowercased(),
                    "CJKSFGSGFR64563RFGY874FG43G784F48FG4F4GF74GF4F7G4FGF4F74F7GFF58Y".lowercased()
                ]

                for index in 0..<SecTrustGetCertificateCount(serverTrust) {
                    let cer = SecTrustGetCertificateAtIndex(serverTrust, index)

                    if let certificate = SecTrustGetCertificateAtIndex(serverTrust, index) {
                        let certData = certificate.data
                        let certHashByteArray = certData.sha256()
                        let certificateHexString = certHashByteArray.toHexString().lowercased()

                        if fingerPrints.contains(certificateHexString) {
                            return (disposition, credential)
                        }
                    }
                }
            }
        }
        disposition = .cancelAuthenticationChallenge
        return (disposition, credential)
    }
    return man
}()

Для преобразования SecTrustGetCertificateAtIndex(serverTrust, index) (эта строка let certData = certificate.data) используйте это расширение

import Foundation
public extension SecCertificate {
    public var data: Data {
        return SecCertificateCopyData(self) as Data
    }
}

Для этих двух строк я использовал библиотеку CryptoSwift, вместо нее вы можете использовать sha1 of sha256, Прикрепил сертификат с отпечатком пальца sha256.

let certHashByteArray = certData.sha256()
let certificateHexString = certHashByteArray.toHexString().lowercased()
2
Hamed 16 Мар 2019 в 11:54

Могу я спросить причину, по которой вы пытаетесь закрепить отпечаток пальца вместо открытого ключа или сертификата?

По моему опыту, ключевым моментом закрепления является жесткое кодирование чего-либо в вашей программе.

К вашему сведению: https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning

0
NINJAJA 10 Май 2016 в 03:45