27

We have an iOS app that uses a UIWebView to display content. We load it up with data with code that looks like this:

NSURL *url = [NSURL URLWithString:myURLString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[_webView setDelegate:self];
[_webView loadRequest:request];

This used to work fine with HTTP requests, but now we are using HTTPS against a server with a self-signed SSL certificate. When the above is run, the webView:didFailLoadWithError: delegate method gets called, with this error:

The certificate for this server is invalid. You might be connecting to a server that is pretending to be "blah.blah.blah.com" which could put your confidential information at risk."

I would like to simply ignore the invalid certificate and go on with the request, as one can do in Mobile Safari.

I have seen how to work around this issue when using NSURLConnection (see HTTPS request on old iphone 3g, for example), but what can one do with a UIWebView?

I imagine that I could rework the code so that it uses NSURLConnection to make the requests and then puts the results into the web view by calling its loadHTMLString:baseURL: method, but that's going to get complicated when the pages have images, CSS, JavaScript, and so on. Is there an easier way?

Community
  • 1
  • 1
Kristopher Johnson
  • 76,675
  • 54
  • 235
  • 299

4 Answers4

22

Please note: This API is currently unsupported, and should really only be used in a safe testing environment. For further details, take a look at this CocoaNetics article.

[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[url host]]; will allow you to ignore certificate errors. You will also need to add the following to the beginning of your file to grant you access to these private APIs:

@interface NSURLRequest (DummyInterface)
+ (BOOL)allowsAnyHTTPSCertificateForHost:(NSString*)host;
+ (void)setAllowsAnyHTTPSCertificate:(BOOL)allow forHost:(NSString*)host;
@end
Darc
  • 687
  • 1
  • 6
  • 12
17

Just so everyone knows... the above use of hidden interfaces WILL NOT BE ACCEPTED BY APPLE. They look for use of private APIs and it is NOT an acceptable solution. So, please do not go posting the solution described above around as THE way to fix it because, although it works, it will buy you a rejection in the AppStore. That makes it useless.

What follows is the ACCEPTABLE method of ignoring invalid server certificates. You need to use NSURLConnection and load the data for the webpage manually like so:

.
.
.
    //Create a URL object.
    url = [NSURL URLWithString:urlAddress];
    NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:requestObj delegate:self];
    [connection start];
}

And then, in your delegate....

- (BOOL)connection:(NSURLConnection *)connection canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace 
{
    return [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust];
}

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge 
{
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
    {
        [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
    }
    else
    {
        [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
    }
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 
{
[resultData appendData:data];
}


- (void)connectionDidFinishLoading:(NSURLConnection *)connection 
{
    NSString *htmlString = [[NSString alloc] initWithBytes:[resultData bytes] length:[resultData length] encoding:NSUTF8StringEncoding];
    [webView loadHTMLString:htmlString baseURL:url];
}
@end

Where resultData is an NSMutableData you instantiated earlier and where url and urlAddress are both things you've instantiated and filled in elsewhere.

Unfortunately, I currently don't know a way to get the actual UIWebView to load a page directly without having a valid certificate.

Yours, GC

greg.casamento
  • 343
  • 2
  • 5
  • 2
    problem with this approach is that your webview will not show any dynamic content - CSS won't load, javascript or any embedded REST calls etc. This is my problem at the moment. There's a convoluted way of doing it suggested [here](http://stackoverflow.com/questions/11573164/uiwebview-to-view-self-signed-websites-no-private-api-not-nsurlconnection-i) – Stretch Jul 25 '12 at 01:05
  • This isn't an acceptable solution for dynamic web pages that eg. have javascript that depend on window.location after redirects. The UIWebView itself needs to manage its location and handle redirects, something that can't be done by feeding it data from an NSURLConnection. – davidgoli Feb 27 '14 at 01:06
3

It turns out that once the site is authenticated by a cancelled NSURLConnection, the UIWebView can make requests to the site. There is a complete explanation here.

Community
  • 1
  • 1
Prof Von Lemongargle
  • 3,488
  • 26
  • 28
  • This answer: http://stackoverflow.com/questions/11573164/uiwebview-to-view-self-signed-websites-no-private-api-not-nsurlconnection-i/15074358#15074358 has a clever way around this problem. – zadr Dec 26 '13 at 19:30
0

As far as I know, that isn't possible with just UIWebView. As I understand it, you need to use NSURLConnection to handle all the HTTP/HTTPS mojo and then feed its results to the UIWebView via -loadHtmlString:baseURL: or -loadData:MIMEType:textEncodingName:baseURL:.

Greg
  • 9,304
  • 5
  • 39
  • 62