Alex Dieulot
Simplicity and avant-gardism

How to bypass iOS 9 content blocking

This article explains how scripts will need to evolve to escape iOS 9’s content blocking mechanism.

How third-party scripts operates

Currently, third-party vendors give website owners a snippet of JavaScript to insert into their sites’s pages. This snippet loads a JavaScript file from the vendor’s site (such as http://script.vendor.com/analytics.js), and this loaded file then usually reports informations to another URL on the vendor’s site (such as http://script.vendor.com/collect.php).

Content blockers have it easy, they just need to block the requests from all the most used domains of those vendors (here, script.vendor.com, or even vendor.com).

Constrained devices

iOS devices are constrained on memory, processing power, and battery; thus content blockers can’t block too many different things.

From Marco Arment, who did Peace:

Since the browser must check every resource against the blocklist as a page loads, and modern pages commonly include tens or hundreds of resources, bigger isn’t better. The bigger the list, the more time and memory necessary to enforce its rules as pages load.

Diminishing returns set in quickly: the ideal list has just enough entries to block most ads and trackers that we’ll encounter on most sites we’ll visit, but not so many that we’re burdening Safari with thousands of entries it will probably never use.

Marco’s app had a blocklist of about 2,000 entries, and he calls it “reasonably sized”.

The future: first-party subdomains

Third-party scripts, in order not to be blocked, need to not be identifiable by a simple blocking rule.

A very effective way to do that is to make them look like first-party scripts.

The solution is pointing a site’s subdomain to the vendor’s server, via DNS. This doesn’t compromise convenience too much — adding a DNS record isn’t as widespread a practice as adding a snippet of code into webpages, but the learning curve is similarly small — and it works. Vendors now have a different domain used for each site they serve.

Content blockers now can’t just block the most popular scripts without impacting performance (and putting a tremendous amount of work into maintaining those hypothetical lists); and iOS doesn’t grant content blockers access to Safari’s history, thus making it impossible to block content only from the sites a user frequents.

Of course, the subdomain can’t be the same for every domain, otherwise content blockers will be able to block them as easily as today, with just one rule. It needs to be a random string of character for each site. Something like http://qngosjscn.mysite.com/analytics.js.

The analytics.js part may be stealthy too. It can be a random string of characters of random length without any file extension. Same thing for the collect.php part. The vendor’s webserver can differentiate the two with different ranges of length, or by using a specific character (such as a slash) only for collect.php.

Why would content blockers not block every subdomain of the most popular sites using this? Because there usually are “legit” files on subdomains. And when there isn’t any for a specific site, you’re still unsure about the future. It’s a losing bet. (Same thing with blocking all the subdomains but one or two.)

Blocking cookies of subdomains

One thing iOS content blockers can do is to not send cookies to subdomains from sites using these scripts. But you would still need a content blocking rule for every site, leading to degraded performance.

Also, there are lots of ways to make good educated guesses without cookies to keep track of someone.

Subdomains prepared in advance

For extra resilience to content blockers, script vendors could ask websites to make multiple subdomains pointing to their server, so that when the first one is blocked, a site just has to change the subdomain used in the JavaScript snippet.

Technical example

The script vendor asks the website to add a DNS record pointing to their server’s IP (either with an A or a CNAME record) to three subdomains, such as “wnhi”, “rfzoajsm”, and “qdizngspn”.

The snippet to insert on the website’s page is this:

<script> (function() { // Generate an alphanumeric string with a length between 3 and 8 var random = Math.random().toString(36).substr(2, 3.5 + Math.random() * 5); // Load the script var script = document.createElement('script'); script.async = true; script.src = '//wnhi.mysite.com/' + random; document.body.appendChild(script); })(); </script>

The script then does its thing, and reports informations to another random URL on the same domain, just with a different range of length for its name.

If this subdomain ever gets blocked (which I think won’t happen often in practice), the site has two others subdomains ready, and just need to replace the “wnhi” part in the JavaScript snippet.

How to fix it

Apple would need to allow content blockers to not only block specific URLs, but IP addresses as well. Once that happens, script vendors likely won’t be able to get their hands on enough IPs to make this technique work.

It’s not a given that it will happen. If it does happen, the most likely date for it is September 2016, when iOS 10 comes out.

Update: If that happens, the only option left for venders will be to make the site host the files, or a proxy of the files. This isn’t nearly as trivial to do due to sites’ differing architectures, but it’s an option.

Conclusion

To circumvent iOS 9 content blocking, scripts now have to operate on a single subdomain, which means that cross-domain tracking — the creepiest stuff — is gone. Non-creepy ads and trackers (statistics) can still live peacefully, with some technical adjustments.

hint, hint