WKWebView - Redirect from https to http site?

Hi! I know this is a WKWebView question, but it has enough to do with core networking that I thought I would put it here.


We're implementing a WKWebView in our application but having a problem with our Wifi portal. We start with an HTTPS link, and then our wifi redirects it to a wifi login page. The redirect makes WKWebView consider this an SSL failure. I don't even get a callback to accept the authentication challenge through the navigation delegate.


If I load this URL in Safari, it shows a dialog about the SSL failure, but gives me a continue button. Is there a way to implement similar funcitonality for a WKWebView?

Is there a way to implement similar funcitonality for a WKWebView?

Yes, via the authentication challenge handler. Your handler will be called with a

NSURLAuthenticationMethodServerTrust
authentication challenge. You can do whatever trust evaluation you want and then, when you’re done, call the completion handler with one of the
NSURLSessionAuthChallengeDisposition
values to indicate your result. This typically means
NSURLSessionAuthChallengeUseCredential
to allow the request or
NSURLSessionAuthChallengeCancelAuthenticationChallenge
to deny it.

Keep in mind that this delegate is async, so you can actually put up UI if you want. However, I strongly recommend that you not pass this decision on to the user, but instead come up with a trust evaluation strategy that can securely check the identity of your portal without user interaction.

For more background on this see Technote 2232 HTTPS Server Trust Evaluation. This technote hasn’t been updated for WKWebView, so you won’t find details on that there, but the WKWebView authentication challenge mechanism is virtually identical to the NSURLSession one.

IMPORTANT Two things to note here:

  • WKWebView’s authentication challenge mechanism was introduced with WKWebView itself, back in iOS 8. However, this didn’t work for

    NSURLAuthenticationMethodServerTrust
    until iOS 9.
  • Moreover, it still does not work for

    NSURLAuthenticationMethodClientCertificate
    challenges. That’s unlikely to be a problem for you but it’s an ongoing pain point for other developers.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

If you mean:

func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)


That is never being called. Instead it skips straight to:

func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error)


With the error:

Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={_kCFStreamErrorDomainKey=3, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorCodeKey=-9824, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., _WKRecoveryAttempterErrorKey=<WKReloadFrameErrorRecoveryAttempter: 0x174229720>, NSErrorFailingURLKey=https://labs-resolver.digimarc.net/api/v2/linkcpm/GC41.KE.WOM1.v5R.11CF4499, NSUnderlyingError=0x174056bc0 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, _kCFNetworkCFStreamSSLErrorOriginalValue=-9824, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9824}}, NSErrorFailingURLStringKey=https://labs-resolver.digimarc.net/api/v2/linkcpm/GC41.KE.WOM1.v5R.11CF4499}

If you mean:

func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)

Yes.

That is never being called.

Hmmm.

With the error:

OK, that explains things. The TLS connection isn’t failing with a server trust evaluation problem, it’s failing with a general TLS handshake problem. Note the underlying error code here, -9824, or

errSSLPeerHandshakeFail
.

It’s quite possible that this error is the result of App Transport Security (my ATS pinned post has lots of background on this, including links to the official documentation). I recommend that you test this theory by temporarily disabling ATS entirely via the

NSAllowsArbitraryLoads
key. If ATS is the issue, that will get it out of the way and allow the authentication challenge delegate method to be called. And once you’ve confirmed that, you can craft a more focused ATS exception dictionary.

OTOH, if

NSAllowsArbitraryLoads
doesn’t help, you are looking at a real TLS handshake failure, which is an entirely different kettle of fish.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

ATS is already disabled in this application, so I guess I'm with the entirely different kettle of fish. 🙂


It's possible this is just a defect in our on site captive wifi so I may head out and test with other captive wifi access points. I don't know enough about encryption to really define to our internal IT staff what is going on though.

ATS is already disabled in this application …

Bummer.

The next step here is to take a packet trace of the failing case and a packet trace of the working case to see where the TLS handshakes diverge. You can get a packet trace from the perspective of iOS using the RVI mechanism discussed in QA1176 Getting a Packet Trace.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
WKWebView - Redirect from https to http site?
 
 
Q