ios9xcode7nsapptransportsecurity

NSAppTransportSecurity: Not working with correct settings


As many developers out there I get some data from a webserver via http. Since XCOde7/iOS9 I need to mark the used domains as an exception in my apps plist. This worked out for all of my domains except one.

Important: It is no solution for me to accept all domains with NSAllowsArbitraryLoads. First I tried the following entries in the plist:

<key>cc.mydomain.de</key>
        <dict>
            <key>NSIncludesSubdomains</key>
            <true/>
            <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>

This configuration worked for all the other domains but not for this one so I added the following entries to the plist:

<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
     <false/>
<key>NSThirdPartyExceptionAllowsInsecureHTTPLoads</key>
     <true/>
<key>NSExceptionRequiresForwardSecrecy</key>
    <false/>

But I still got an error when trying to access the domain.

App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file

If these exception entries dont work then what is working? What is the minimum configuration for an exception like that. Which entry am I missing?


Solution

  • I contacted Apple Developer support for this issue and they told me the problem is that one of my urls redirects to another url which of course has to be listed as an exception in my plist, too. You can easily determine the redirection with the url session delegate method for redirection:

    self.session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration(), delegate: self, delegateQueue: NSOperationQueue.mainQueue())
    
    let url = NSURL(string: "yoururl")!
    
    self.session.dataTaskWithURL(url) { (data, response, error) in
        if let error = error {
            NSLog("error %@ / %d", error.domain, error.code)
        } else if let response = response as? NSHTTPURLResponse {
            NSLog("response %d", response.statusCode)
        } else {
            fatalError()
        }
    }.resume()
    
    func URLSession(session: NSURLSession, task: NSURLSessionTask, willPerformHTTPRedirection response: NSHTTPURLResponse, newRequest request: NSURLRequest, completionHandler: (NSURLRequest?) -> Void) {
            NSLog("direct to %@", request.URL!)
            completionHandler(request)
    }
    

    Swift 3 version:

    class ViewController: UIViewController, URLSessionTaskDelegate {
    
        var session: URLSession! = nil
    
        override func viewDidLoad() {
             super.viewDidLoad()
    
             self.session = URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: OperationQueue.main)
    
             let url = NSURL(string: "yoururl")!
    
             self.session.dataTask(with: url as URL) { (data, response, error) in
                 if let error = error {
                     NSLog("error %@ / %d", (error as NSError).domain, (error as NSError).code)
                 } else if let response = response as? HTTPURLResponse {
                     NSLog("response %d", response.statusCode)
                 } else {
                     fatalError()
                 }
                 }.resume()
         }
    
         func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) {
             print("direct to %@", request.url!)
             completionHandler(request)
         }
    }