2

I have seen various example online saying how to accept them but I always get An SSL error has occurred and a secure connection to the server cannot be made.

I will note than the method is definitely being called (running on an iOS 8.4 simulator and an iOS 11 actual device), so the method not being called is not the issue here.

What I have tried so far (obviously I only use this code in development and not in production, blah blah blah):

1:

public override void DidReceiveAuthenticationChallenge(WKWebView webView, NSUrlAuthenticationChallenge challenge, Action<NSUrlSessionAuthChallengeDisposition, NSUrlCredential> completionHandler) {
 completionHandler(NSUrlSessionAuthChallengeDisposition.UseCredential, new NSUrlCredential(serverTrust));
}

2:

public override void DidReceiveAuthenticationChallenge(WKWebView webView, NSUrlAuthenticationChallenge challenge, Action<NSUrlSessionAuthChallengeDisposition, NSUrlCredential> completionHandler) {
 completionHandler(NSUrlSessionAuthChallengeDisposition.UseCredential, NSUrlCredential.FromTrust(serverTrust));
}

3:

    public override void DidReceiveAuthenticationChallenge(WKWebView webView, NSUrlAuthenticationChallenge challenge, Action<NSUrlSessionAuthChallengeDisposition, NSUrlCredential> completionHandler) {
        SecTrust serverTrust = challenge.ProtectionSpace.ServerSecTrust;
        NSData exceptions = serverTrust.GetExceptions();
        serverTrust.SetExceptions(exceptions);
        exceptions.Dispose();
        completionHandler(NSUrlSessionAuthChallengeDisposition.UseCredential, NSUrlCredential.FromTrust(serverTrust));
    }

4:

    public override void DidReceiveAuthenticationChallenge(WKWebView webView, NSUrlAuthenticationChallenge challenge, Action<NSUrlSessionAuthChallengeDisposition, NSUrlCredential> completionHandler) {
        SecTrust serverTrust = challenge.ProtectionSpace.ServerSecTrust;    //TODO: Get the following working (currently we still receive SSL errors)
        NSData exceptions = serverTrust.GetExceptions();
        serverTrust.SetExceptions(exceptions);
        exceptions.Dispose();

        challenge.Sender.UseCredential(NSUrlCredential.FromTrust(serverTrust), challenge);
        completionHandler(NSUrlSessionAuthChallengeDisposition.UseCredential, NSUrlCredential.FromTrust(serverTrust));
    }

What am I doing wrong? Thanks.

hvaughan3
  • 10,955
  • 5
  • 56
  • 76

1 Answers1

9

To support self-signed certs you have two things to do:

  1. Allow NSExceptionAllowsInsecureHTTPLoads on your self-signed domain
    • Even though you are using https, your app is flagged as having a trust issue
  2. Bypass certificate security checking

Security Note on 2: Get a CA-issued certificate for any production apps as this completely disables certificate validation on your domain and thus allowing MITM attacks, DNS redirection spoofing of your app, etc... You could pin the cert by including the public cer in the main bundle and checking it against the cert received, but that just means a fake certificate would need to be generated in either the MITM or DNS spoofing attack (and tools for those already exist in the various exploit kits)

Example using the https://badssl.com site:

WKNavigationDelegate:

public class NavigationDelegate : WKNavigationDelegate
{
    const string host = "self-signed.badssl.com";
    public override void DidReceiveAuthenticationChallenge(WKWebView webView, NSUrlAuthenticationChallenge challenge, Action<NSUrlSessionAuthChallengeDisposition, NSUrlCredential> completionHandler)
    {
        switch (challenge.ProtectionSpace.Host)
        {
            case host:
                using (var cred = NSUrlCredential.FromTrust(challenge.ProtectionSpace.ServerSecTrust))
                {
                    completionHandler.Invoke(NSUrlSessionAuthChallengeDisposition.UseCredential, cred);
                }
                break;
            default:
                completionHandler.Invoke(NSUrlSessionAuthChallengeDisposition.PerformDefaultHandling, null);
                break;
        }
    }
}

Note: Assign an instance of this class to the NavigationDelegate or WeakNavigationDelegate of your WKWebView instance.

Info.plist NSAppTransportSecurity:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>self-signed.badssl.com</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
    </dict>
</dict>
SushiHangover
  • 73,120
  • 10
  • 106
  • 165
  • Thank you! I added your code along with the `NSExceptionAllowsInsecureHTTPLoads` in my info.plist, uninstalled the app, rebuilt and deployed and am now seeing that, after a redirect from the original site to a login site (also with a self-signed cert), navigation is failing in `DidFailProvisionalNavigation` with the following error: **The certificate for this server is invalid. You might be connecting to a server that is pretending to be “login.somesite.dev” which could put your confidential information at risk.** – hvaughan3 Nov 21 '17 at 14:55
  • @hvaughan3 You have multiple self-signed sites/domains? Or are they subdomains of one self-signed domain? Wild-card self-signed? etc... – SushiHangover Nov 21 '17 at 14:57
  • All of the sites in the .dev environment are using ugly, self-signed certs. So when I hit site1.somesite.dev and am not logged in, it redirects to login.sometime.dev to force me to login. Both sites use self-signed certs, not sure if they are the same self-signed certs. And actually, it is working on my iOS 11.1.2 device, but not on my iOS 8.4 simulator so it looks like there was a bug that was fixed. Thank you again very much! Been wanting to get this done for a long time. – hvaughan3 Nov 21 '17 at 15:00
  • 1
    @hvaughan3 I know that cert bypass code works on iOS 9/10/11+ (that is both device & sim), but iOS 8(.4)? I *think* there were Apple `radr` that stated problems w/ ATS, self-signed certs and UIWebView/MKWebView, but can not remember off the top of my head. – SushiHangover Nov 21 '17 at 15:09