Connect to a Server with Invalid Certificate using NSURLSession (swift2,xcode7,ios9)

18,109

Solution 1

Take a look at this article.Shipping an App With App Transport Security particularly the sections about self-signed certificates.

You'll most likely need the delegate method of the form,

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

Adding this to my own comms class that uses NSURLSession fixed the issue.

Solution 2

When creating the URL Session, use the initializer, that sets the delegate along with the configuration, like below:

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

Then, implement the following delegate method, it should work.

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

However, it is very important to note, that this is a security issue, and we should not be trying to connect to servers with invalid certificates.

Solution 3

Many of the answers are almost there, but not quite. So here is what worked for me on Xcode 12.4

In my Requesting Class

    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)
    }

Where:

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)
        }
    }
}
Share:
18,109
cakes88
Author by

cakes88

Love to make testing software easier.

Updated on June 19, 2022

Comments

  • cakes88
    cakes88 almost 2 years

    I'm using Xcode 7, Swift 2, and iOS9. I want to connect to a web service using NSURLSession but I get the following error when I try to connect:

    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?,
    

    Here is my code:

    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)
            });
    

    I've looked into NSURLAuthenticationChallenge but I can't seem to figure that out with the code I currently have in place. So my question is how can I connect to the server anyway? I've already tried adding the domain to my NSAppTransportSecurity in Info.plist but that did not work. Turning on NSAllowsArbitraryLoads didn't work either. Any help would be appreciated.

    • Code Different
      Code Different over 8 years
      Check out this question on SO: stackoverflow.com/questions/933331/…
    • cakes88
      cakes88 over 8 years
      @ZoffDino that's using NSURLConnection which is deprecated in iOS8. I'd like to use NSURLSession if possible.
    • Jacob King
      Jacob King over 8 years
      The AFNetworking library has excellent support for this, I would recommend checking it out.
  • FractalDoctor
    FractalDoctor over 8 years
    I don't see how this helps, as you're really just bypassing the IP addresses that the app talks to and not anything to do with server certificates?
  • Sumit
    Sumit over 7 years
    i added delegate but this method never called in swift 3, any other solutions without using alamofire or any other lib?
  • Jayprakash Dubey
    Jayprakash Dubey about 7 years
    @Marcelo : NSAllowsArbitaryLoads key when set to true will allows access to all unsecured URLs. So what is the point of having CER file for security?
  • Muhammad Danish Qureshi
    Muhammad Danish Qureshi over 2 years
    Thanks...! This answer is very useful and worked with me in Swift 5 and Xcode 13.1.