For the last few years Apple has developed a privacy-focused brand. Unlike other big tech companies its business model which relies mostly on selling hardware, doesn’t require the company to sell your data.
Ever since iOS 9 Apple has been rolling out privacy protection features like Safari content blocking extensions and most recently cross-site tracking protection enabled by default since iOS 11.
In this tutorial, I’ll show you how to build a simple cross-site tracker blocker for mobile Safari. We’ll build a Safari extension which would block third-party tracking sites based on a black list.
Creating iOS extension
We are going to start with creating a new Single View App project in Xcode and adding a new Content Blocker Extension target (File -> New -> Target…). In the following popup window make sure to activate the newly created target.
If you look into the content of the content blocker extension you can find a file called blockerList.json which contains a simple blocking rule based on URL filtering:
We are going to use the following regex for the domains in the blacklist:
This would allow us to block any requests containing tracker sites in their URLs.
You can ship the blacklist bundled with your app, but we are going to implement live blacklist fetching to guarantee we have the most up-to-date data. We are going to fetch the tracker blacklist, parse it and convert it into blockerList.json format.
We are going to use Alamofire HTTP library to fetch the data:
Then, we’d convert this list of tracker domains into blockerList.json dictionary like this:
If you install the app and enable content blocking in Settings -> Safari -> Content Blockers, it’ll use the bundled JSON file by default.
To configure which blocker list JSON the content blocker extension is going to use, you’d need to change a few lines of code in ContentBlockerRequestHandler.swift inside of your extension.
The plan is to load the blacklist from the main app and somehow make it available to the extension. We can’t overwrite the bundled JSON files and we can’t write to the documents folder, as it’s not accessible to the extension. What’s the solution?
App Groups and Secure Containers
To pass the data between the main app and the content blocking extension, you can use App Groups and write the JSON to the secure container associated with the group.
First you need to create and configure app groups in your main app, as well as in your extension.
Make sure both the main app target and extension target contain the same app group in their entitlements.
The only thing left to do is to write the JSON files to the secure container and then read the file from the extension. Here is how you write the data:
Make sure you are providing the correct name for your app group here.
Finally, you need to reload the content blocking rules here so that the extension picks up the most recent version of the blacklist:
Make sure you are using the bundle identifier of your app extension here.
Now, the JSON file with tracker blocker rules is fetched and stored in the secure app group container. Let’s read this file from the extension:
You can test your tracker blocking extension with the following tools:
Here are the results I’m getting from the tests above:
Now, the results from Panopticlick don’t appear to be optimal, somehow I’m getting “partial protection” and it’s not quite clear what it means. Regardless, the tracker blocker is extremely simple and would only protect you against the basic tracking techniques, for example it wouldn’t cover scenarios when the site is fingerprinting you directly, i.e. doesn’t rely on third-party trackers.
If you want to check out the source code for the final app, you can find it here: https://github.com/nderkach/TrackerBlockeriOS