Comment ajouter l'épinglage de certificat à une session NSURL dans Swift?
Le site Web OWASP ne contient qu'un exemple pour Objective-C et NSURLConnection.
Attention, SecTrustEvaluate
est obsolète et devrait être remplacé par SecTrustEvaluateWithError
.
Donc ça:
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
}
}
La raison pour laquelle j'ai écrit le // Proceed with evaluation
est parce que vous devez valider le secresult
et cela pourrait impliquer que le certificat n'est pas valide. Vous avez la possibilité de remplacer cela et d'ajouter tous les problèmes soulevés en tant qu'exceptions, de préférence après avoir invité l'utilisateur à prendre une décision.
Devrait être ceci:
if SecTrustEvaluateWithError(server, nil) {
// Certificate is valid, proceed.
}
Le deuxième paramètre capturera toute erreur, mais si vous n'êtes pas intéressé par les détails, vous pouvez simplement passer nil
.
Vous pouvez essayer ça.
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)
}
}
Source: https://www.steveclarkapps.com/using-certificate-pinning-xcode/