-
Notifications
You must be signed in to change notification settings - Fork 41
Open
Labels
enhancementNew feature or requestNew feature or request
Description
Great project but there is a weakness, how do we pin a SSL certificate? Otherwise anyone could just use Proxyman and do a man-in-the-middle attack to see what the app is sending out (such as api key etc)
I can use this code below with a normal URL connection and pin the certificate down like that. But how can I integrate this urlSession with swift-EventSource? I couldn't find a way yet...
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
// Helper function to check for subdomains
func containsSubdomain(host: String, subdomains: [String]) -> Bool {
// Split the host into components
let hostComponents = host.split(separator: ".")
// Ensure there are enough components to check for subdomain
guard hostComponents.count > 2 else { return false }
// The subdomain is the first component of the host
let subdomain = String(hostComponents[0])
// Check if the subdomain matches any of the given subdomains
return subdomains.contains(subdomain)
}
// Extract the host from the protection space
let host = challenge.protectionSpace.host
// Check if the current server type is not production
if Constants.currentServerType != .production {
// If not in production, bypass the certificate pinning check
LogService.shared.logInfo("Bypassing certificate pinning check for non-production server.")
completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
return
}
// Proceed with certificate pinning check for production server
guard let serverTrust = challenge.protectionSpace.serverTrust else {
LogService.shared.logCritical("No server trust provided")
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
var error: CFError?
guard SecTrustEvaluateWithError(serverTrust, &error) else {
if let cfError = error {
let nsError = cfError as Error as NSError
LogService.shared.logCritical("SecTrustEvaluateWithError failed.", nsError)
} else {
LogService.shared.logCritical("SecTrustEvaluateWithError failed.")
}
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
guard let certificateChain = SecTrustCopyCertificateChain(serverTrust) as? [SecCertificate],
let serverCertificate = certificateChain.first else {
LogService.shared.logCritical("Failed to get server certificate from chain.")
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
let serverCertificateData = SecCertificateCopyData(serverCertificate) as Data
let decryptedBase64Certificate = Keys.Global().apiCert
guard let localCertificateData = Data(base64Encoded: decryptedBase64Certificate) else {
LogService.shared.logCritical("Failed to decode local certificate from base64.")
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
if serverCertificateData == localCertificateData {
LogService.shared.logInfo("Server certificate matches pinned certificate.")
let credential = URLCredential(trust: serverTrust)
completionHandler(.useCredential, credential)
return
} else {
LogService.shared.logCritical("Server certificate does not match pinned certificate.")
delegate?.didReceiveCertificateMismatchError() // Notify the delegate
}
completionHandler(.cancelAuthenticationChallenge, nil)
}
```
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request