Bug in iOS 11: Safari Mobile sometimes not loading script files when using a Self-Signed Certificate

Summary

I have found a bug in Mobile Safari in iOS 11 (but not iOS 10) that causes javascript applications to fail when they are loaded from a webserver using a self-signed certificate, are loaded soon after Safari was started and work by including other javascript files from the same host.

How to reproduce the bug

My setup uses an IIS (Microsoft Internet Information Services) which has SSL enabled and uses a self-signed certificate create from within IIS. There is a directory with the content of this zip archive.. There is basically one simple html page that looks like this:

<html>
<head>
<script>
var counter = 0;
</script>
<script src="JS/1.js"></script> 
<script src="JS/2.js"></script> 
<script src="JS/3.js"></script> 
<script src="JS/4.js"></script> 
<script src="JS/5.js"></script> 
<script src="JS/6.js"></script> 
<script src="JS/7.js"></script> 
<script src="JS/8.js"></script> 
<script src="JS/9.js"></script> 
<script src="JS/10.js"></script>
<script src="JS/11.js"></script>
<script src="JS/12.js"></script>
<script src="JS/13.js"></script>
<script src="JS/14.js"></script>
<script src="JS/15.js"></script>
<script src="JS/16.js"></script>
<script src="JS/17.js"></script>
<script src="JS/18.js"></script>
<script src="JS/19.js"></script> 
</head>
<body>
Hello World!
<script>
document.write(counter);
</script>
</body>
</html>

And all the referrenced JavaScript files exist all with the same content:

document.write("X");
counter++;

What we expect to happen when opening the html page with a browser is that we see 19 lines with an X, a row saying “Hello World!” and then the number 19. When this specific bugĀ  occurs, we do see fewer lines with an X and a lower number at the end, because some of the included javascript files are not loaded.

How to see the bug in Safari

Open the web page in Safari (on iOS 11) by entering the correct url like in my case on the test server in my local network “https://10.50.75.208/test”. The first time you will be asked by Safari to allow opening this site that does not have a trusted certificate. Confirm that.

When the page was opened and correctly shows the expected result, close Safari by showing the list of running apps on the iOS device and swipe away the Safari app. Then open Safari again. Safari will automatically try to open the same page again. In most cases when doing this, the bug will occur and you will see fewer than expected lines with X and lower number than 19 at the end.

Waiting some time and refreshing the page will then always produce the correct result until you restart Safari again.

This video shows the described behaviour on an iPad.

What the developer tools see

When using the Safari developer tools on a Mac connected to the iOS device, we can see what goes wrong:

A screenshot of the Safari developer tools, showing the resources tab where we see 19 javascript files and some of them marked as red.

Some of the referenced javascript files could not be loaded. The set of javascript files that fail loading changes at every attempt. Sometimes when we are quick enough in opening the developer tools, the console will also give the following error message: “Failed to load resource: The certificate for this server is invalid. You might be connecting to a server that is pretending to be 10.50.75.208 which could put your confidential information at risk.”

Speculation: What’s the bug?

My speculation as to what is happening in Safari internally is the following: When Safari starts, it will try to load the list of accepted untrusted ssl certificates in a background task. For some reason, accessing this list and loading this list is not correctly synchronized so that during a short period after starting Safari, a check will be made against the list although is has not been fully loaded and the loading of some referrenced resources will then fail because the untrusted certificate used is not found in the incompletely loaded list..

Workaround

The only solution to this problem I have found is to not use a self-signed certificate. You need to actually create your own local CA (Certiciate Authority), install this CA’s public certificate on the iPad, manually enable that it is trusted as a CA, then use this CA to create an SSL certificate and then install and use this SSL certificate in IIS (or some other webserver software)

Leave a Reply

Your email address will not be published. Required fields are marked *