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 . Even if you trust the extension's authors today, the headline "Firms buy popular Chrome extensions to inject malware, ads" should give you pause . 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. " 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"] . 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/*". 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
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.
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.
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!