This article covers the basics of writing chrome extensions by building a simple adblocker. It also explains how adblock detection works.
I rarely feel compelled to use an adblocker. This is partly because most pages I view have few, if any, ads, but the main reason is I'm wary of 3rd party browser extensions. Adblock Plus can "Read and change all data on the website you visit." This makes sense, because the extension is removing elements from the webpages you visit. Unfortunately these permissions allow for plenty of mischief [1]. Even if you trust the extension's authors today, the headline "Firms buy popular Chrome extensions to inject malware, ads" should give you pause [2]. Luckily it does not take much work to write a blocker yourself.
Chrome extensions are build using standard web technologies. The primary differences between an extension and a web app are that extensions have access to additional browser specific APIs and run differently that normal pages.
To start off, create a new folder with the name of your extension and add the following file "manifest.json" to it. The manifest is an "index" of the extension and most of the fields are self explanatory.
The permissions field lists what webpages the extension has permission to access. We want our extension to have access to all pages, hence the wildcard patterns. Note: permission to access an http page is distinct from permission for the https equivalent. The permission field also lists which "special" APIs and feature we wish to make use of.
Our extension will run in the background and automatically intercept and filter requests. To set this up we give a list of scripts to load and run in the background. The order of scrips is important so make sure to list a script after its dependencies. We will fill in the scripts later, but for now just create a blank file for each and add the line console.log("My chrome extension works!!!");
to background.js.
To test an extension go to chrome://extensions and check the developer mode box. Now click load unpacked extensions and select the folder containing the extension's code and manifest.
Clicking on the background page link should bring up the Developer Tools. Now go to the console tab. Any output or error messages should be displayed here. Additionally you can access the standard debugging tools from here.
The plan for the blocker is to intercept requests and block ones to domains hosting ads. Perusing the chrome docs reveals the chrome.webRequest.onBeforeRequest
event. The onBefore request "Fires when a request is about to occur. This event is sent before any TCP connection is made and can be used to cancel or redirect requests. "[3] All we have to do is copy and past the example to get version one of our blocker.
Adblockers are glorified blacklists. uBlockOrigin has all sorts of complicated rules for matching specific page elements such as google.*###rhs_block .mod > .luhb-div > div[data-async-type="updateHotelBookingModule"]
[4]. To keep the blocker simple, we will only pay attention to domain names. A list of domains to block is available at github.com/StevenBlack/hosts.
The entries are in the format of a host file ex: 0.0.0.0 tracking.klickthru.com
. Chrome expects specific url patterns, so we need convert the entries to look like "*://*.tracking.klickthru.com/*"
[5]. Additionally, empty lines and comments need filtering out. Lots of trial and error yields the following magic incantation. In retrospect, writing a python script to do this would have been easier.
grep "^0\.0\.0\.0" hosts | cut -d ' ' -f2 | sed 's/\([^\n]*\)/"*:\/\/*.\1\/*",/' > blocked_domains.js
Now edit the first and last lines of blocked_domains.js so that it is a valid JavaScript array that looks like this:
Also remember to update background.js to use our new list.
I tried the extension on cnn's website. Looking at the network activity page reveals that the extension is blocking lots of requests. The domains being blocked look like mostly 3rd party ad and analytics domains. The page has no immediately visible ads, so the extension is working.
Most adblockers remove elements that look like ads. To detect an adblocker, a site will set a "honeypot" element that looks like or is an ad and checks to see if the element is removed. Because our blocker blocks requests rather than removing page elements, current blocker blockers do not detect it (go to forbes.com which has ads galore if you want to see this for yourself).
There is a possibility that this extension could break the main functionality of some sites. So let's add an enable/disable button. The first step is to update the manifest to specify the location of the html page that will show when the extension's icon is clicked on.
Now create fill out popup.html with a toggle button. Chrome does not like inline JavaScript in extension pages, so the JavaScript to handle button clicks will be in a separate file.
We can access the background page from the UI window using the chrome.extensions.getBackgroundPage method. This method gives access to the background script's window object which exposes all global variables.
Download complete source code from github.com/adrs/dyi-adblocker
So there you have it, a short simple adblocker. The only major problem is keeping the blacklist up to date, but scripts could make that easy. For more examples of chrome extensions see chrome's developer docs. Happy coding!