UIWebView to view self signed websites (No private api, not NSURLConnection) - is it possible?

Viewed 66823

There's a load of questions which ask this: Can I get UIWebView to view a self signed HTTPS website?

And the answers always involve either:

  1. Use the private api call for NSURLRequest: allowsAnyHTTPSCertificateForHost
  2. Use NSURLConnection instead and the delegate canAuthenticateAgainstProtectionSpace etc

For me, these won't do.
(1) - means I can't submit to the app store successfully.
(2) - using NSURLConnection means the CSS, images and other things that have to be fetched from the server after receiving the initial HTML page do not load.

Does anyone know how to use UIWebView to view a self-signed https webpage please, which does not involve the two methods above?

Or - If using NSURLConnection can in fact be used to render a webpage complete with CSS, images and everything else - that would be great!

Cheers,
Stretch.

9 Answers

This is a clever workaround. However, a possibly better (although more code intensive) solution would be to use an NSURLProtocol as demonstrated in Apple's CustomHTTPProtocol sample code. From the README:

"CustomHTTPProtocol shows how to use an NSURLProtocol subclass to intercept the NSURLConnections made by a high-level subsystem that does not otherwise expose its network connections. In this specific case, it intercepts the HTTPS requests made by a web view and overrides server trust evaluation, allowing you to browse a site whose certificate is not trusted by default."

Checkout the full example: https://developer.apple.com/library/ios/samplecode/CustomHTTPProtocol/Introduction/Intro.html

First thing UIWebView is deprecated

use WKWebView instead (available from iOS8)

set webView.navigationDelegate = self

implement

extension ViewController: WKNavigationDelegate {

func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
    let trust = challenge.protectionSpace.serverTrust!
    let exceptions = SecTrustCopyExceptions(trust)
    SecTrustSetExceptions(trust, exceptions)
        completionHandler(.useCredential, URLCredential(trust: trust))
    }

}

And add this in plist with domains you want to allow

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>localhost</key>
        <dict>
            <key>NSTemporaryExceptionAllowsInsecureHTTPSLoads</key>
            <false/>
            <key>NSIncludesSubdomains</key>
            <true/>
            <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
            <true/>
            <key>NSTemporaryExceptionMinimumTLSVersion</key>
            <string>1.0</string>
            <key>NSTemporaryExceptionRequiresForwardSecrecy</key>
            <false/>
        </dict>
    </dict>
</dict>
Related