Xamarin WKWebView Accepting Self-Signed Certificat

2019-04-03 00:39发布

问题:

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.

回答1:

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>