Как принять самоподписанный сертификат SSL с помощью iOS 7 NSURLSession
У меня есть следующий код (быстрая реализация):
func connection(connection: NSURLConnection, canAuthenticateAgainstProtectionSpace protectionSpace: NSURLProtectionSpace) -> Bool
{
return protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust
}
func connection(connection: NSURLConnection, didReceiveAuthenticationChallenge challenge: NSURLAuthenticationChallenge)
{
if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust
{
if challenge.protectionSpace.host == "myDomain"
{
let credentials = NSURLCredential(forTrust: challenge.protectionSpace.serverTrust)
challenge.sender.useCredential(credentials, forAuthenticationChallenge: challenge)
}
}
challenge.sender.continueWithoutCredentialForAuthenticationChallenge(challenge)
}
Он отлично работает в iOS 8.x, , но не работает iOS 7.x
В iOS 7.x у меня есть ошибка:
NSURLConnection/CFURLConnection Ошибка загрузки HTTP (kCFStreamErrorDomainSSL, -9813)
Любая идея?
Спасибо!!!
Ответы
Ответ 1
Оба connection:canAuthenticateAgainstProtectionSpace:
и connection:didReceiveAuthenticationChallenge:
в любом случае устарели в iOS 8, поэтому вы должны использовать другие методы.
То, что я использую в своих проектах, является методом делегата NSURLSessionDelegate. Придерживайтесь этого протокола, затем добавьте этот метод:
func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential!) -> Void) {
completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, NSURLCredential(forTrust: challenge.protectionSpace.serverTrust))
}
Затем, когда вы используете инициализацию NSURLSession, с делегатом, установленным в self. Например:
var session = NSURLSession(configuration: configuration, delegate: self, delegateQueue:NSOperationQueue.mainQueue())
Затем используйте этот экземпляр сеанса для вызова метода dataTaskWithRequest на:
var task = session.dataTaskWithRequest(request){
(data: NSData!, response: NSURLResponse!, error: NSError!) -> Void in
if error != nil {
callback("", error.localizedDescription)
} else {
var result = NSString(data: data, encoding:
NSASCIIStringEncoding)!
}
}
task.resume()
Полный рабочий пример можно найти здесь.
По соображениям безопасности, если вы используете самозаверяющий сертификат, я рекомендую также осуществлять привязку открытого ключа (https://gist.github.com/edwardmp/df8517aa9f1752e73353)
Ответ 2
Наследовать класс с помощью URLSessionDelegate
создать объект сеанса
let config = URLSessionConfiguration.default
let session = Foundation.URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue.main)
let task = session.dataTask(with: httpRequest as URLRequest, completionHandler: {requestData, response, errorData -> Void in
if errorData == nil {
dataCallback(requestData! as NSData)
}
else {
let error = NSError(domain: "Err-1001", code: 11, userInfo:nil)
failureCallback(error)
}
});
task.resume()
Добавить делегат метада
func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
completionHandler(
.useCredential,
URLCredential(trust: challenge.protectionSpace.serverTrust!))
}
Добавьте это в свой файл info.plist
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>xyc.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSExceptionRequiresForwardSecrecy</key>
<true/>
<key>NSExceptionMinimumTLSVersion</key>
<string>TLSv1.2</string>
<key>NSThirdPartyExceptionAllowsInsecureHTTPLoads</key>
<false/>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<true/>
<key>NSThirdPartyExceptionMinimumTLSVersion</key>
<string>TLSv1.2</string>
<key>NSRequiresCertificateTransparency</key>
<false/>
</dict>
</dict>
</dict>