【问题标题】:Connect to a Server with Invalid Certificate using NSURLSession (swift2,xcode7,ios9)使用 NSURLSession (swift2,xcode7,ios9) 连接到具有无效证书的服务器
【发布时间】:2015-10-14 14:33:02
【问题描述】:

我正在使用 Xcode 7、Swift 2 和 iOS9。我想使用 NSURLSession 连接到 Web 服务,但尝试连接时出现以下错误:

2015-10-13 16:07:33.595 XCTRunner[89220:4520715] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)
2015-10-13 16:07:33.604 XCTRunner[89220:4520571] Error with connection, details: Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid. You might be connecting to a server that is pretending to be “domainapi.com” which could put your confidential information at risk." UserInfo={NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x7fac7b6facc0>, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?,

这是我的代码:

func request( dataPost : String, successHandler: (response: String) -> Void)-> String {
        let destination:String =  "https://domainapi.com:8743/WebService/sendData"
        let request = NSMutableURLRequest(URL: NSURL(string: destination as String)!)
        request.HTTPMethod = "POST"
        let postString = dataPost
        request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
        request.setValue("0", forHTTPHeaderField: "Content-Length")
        request.setValue("application/xml", forHTTPHeaderField: "Content-Type")
        request.setValue("gzip,deflate", forHTTPHeaderField: "Accept-Encoding")
        request.setValue("Keep-Alive", forHTTPHeaderField: "Connection")
        NSLog("Body is: %@", request.HTTPBody!)
        NSLog("Request is: %@", request.allHTTPHeaderFields!)
        NSLog("URL is: %@", destination)

        let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
            data, response, error in


            if error != nil {
                NSLog("Error with connection, details: %@", error!)
                return
            }

            let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)

            successHandler(response: responseString as String!);
            NSLog("Data received: %@", data!)

        }

        task.resume()
        return "worked"
    }
    func viewDidLoad() {
        let dataPost : String = "<webservices>xml data sending</webservices>"
        request(dataPost, successHandler: {
            (response) in
            let text = response
            print(text)
        });

我已经查看了NSURLAuthenticationChallenge,但我似乎无法用我目前拥有的代码来解决这个问题。所以我的问题是我如何才能连接到服务器?我已经尝试在 Info.plist 中将域添加到我的NSAppTransportSecurity 中,但这不起作用。打开NSAllowsArbitraryLoads 也不起作用。任何帮助将不胜感激。

【问题讨论】:

  • 在 SO 上查看这个问题:stackoverflow.com/questions/933331/…
  • @ZoffDino 正在使用 iOS8 中已弃用的 NSURLConnection。如果可能,我想使用 NSURLSession。
  • AFNetworking 库对此提供了出色的支持,我建议您查看一下。

标签: xcode swift swift2 ios9 xcode7


【解决方案1】:

看看这篇文章。Shipping an App With App Transport Security 特别是关于自签名证书的部分。

您很可能需要表单的委托方法,

func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
    completionHandler(
        .UseCredential, 
        NSURLCredential(trust: challenge.protectionSpace.serverTrust!)
    )
}

将此添加到我自己的使用 NSURLSession 的 comms 类中解决了这个问题。

【讨论】:

  • 我添加了委托,但此方法从未在 swift 3 中调用过,是否有任何其他解决方案不使用 alamofire 或任何其他库?
【解决方案2】:

在创建 URL Session 时,使用初始化器,它将委托与配置一起设置,如下所示:

let urlSession = URLSession(configuration: urlSessionConfiguration, delegate: self, delegateQueue: nil)

然后,实现下面的委托方法,它应该可以工作了。

func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
    let urlCredential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
    completionHandler(.useCredential, urlCredential)
}

但是,请务必注意,这是一个安全问题,我们不应该尝试连接到具有无效证书的服务器。

【讨论】:

    【解决方案3】:

    很多答案都差不多了,但并不完全。所以这就是在 Xcode 12.4 上对我有用的方法

    在我的请求类中

        let session: URLSession
        let sessionDelegate: HTTPRequestDelegate
        private  init() {
            let configuration = URLSessionConfiguration.default
            // Some more configuration settings
            // ...
    
            sessionDelegate = HTTPRequestDelegate()
            session = URLSession(configuration: configuration,
                                     delegate:  sessionDelegate,
                                     delegateQueue: nil)
        }
    

    地点:

    public class HTTPRequestDelegate: NSObject, URLSessionDelegate
    {
        // Get Challenged twice, 2nd time challenge.protectionSpace.serverTrust is nil, but works!
        public func urlSession(_ session: URLSession,
                        didReceive challenge: URLAuthenticationChallenge,
                        completionHandler: (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
            print("In invalid certificate completion handler")
            if challenge.protectionSpace.serverTrust != nil {
                completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
            } else {
                completionHandler(.useCredential, nil)
            }
        }
    }
    

    【讨论】:

    • 谢谢...!这个答案非常有用,并且在 Swift 5 和 Xcode 13.1 中与我一起使用。
    【解决方案4】:

    将您的 info.plist 作为源代码打开 添加以下内容:

        <key>NSAppTransportSecurity</key>
        <dict>
               <key>NSAllowsArbitraryLoads</key>
              <true/>
       </dict>
    

    这应该会有所帮助。

    【讨论】:

    • 我看不出这有什么帮助,因为您实际上只是绕过了应用程序与之通信的 IP 地址,而与服务器证书没有任何关系?
    • @Marcelo : NSAllowsArbitaryLoads 键设置为 true 时将允许访问所有不安全的 URL。那么拥有 CER 文件的安全性有什么意义呢?
    【解决方案5】:

    我收到错误消息“此服务器的证书无效。您可能正在连接到伪装成“www.yoururl.com”的服务器,这可能会使您的机密信息面临风险。”

    我通过在我的 httpclient 文件中执行此操作解决了这个问题。以下代码将完全忽略身份验证请求。

    var session: URLSession?
    
    session = URLSession(configuration: sessionConfiguration(), delegate: self, delegateQueue: nil)
    
    private func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: (URLSession.AuthChallengeDisposition) -> Void) {
                completionHandler(
                    .cancelAuthenticationChallenge
                )
            }
    

    也不确定它是否会影响上述内容,但在我的 info.plist 中,我将“允许传输安全设置”和子键值选项“允许任意负载”设置为“是”。

    【讨论】:

      【解决方案6】:

      对于 SWIFT 4:

      func URLSession(session: URLSession, didReceiveChallenge challenge: URLAuthenticationChallenge, completionHandler: (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
          completionHandler(
              .useCredential,
              URLCredential(trust: challenge.protectionSpace.serverTrust!)
          )
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多