A lot of people dislike adverts on websites but I'm pretty sure that everyone hates adverts that are a result of malware, ad-injectors or malicious browser extensions. Ad-injectors can destroy the look of a webpage and make it look like you, the host, are pumping out what can often be some pretty inappropriate adverts. In this blog I'm going to look at how easy it can be to combat ad-injectors with nothing more than a single HTTP response header thanks to Content Security Policy.
Content Security Policy
CSP is a single HTTP response header that you can add to your site and provides a huge amount of control to the site admin. When a browser receives a webpage it loads any content that is defined in the page source. That could be images, videos, scripts, style sheets and much, much more. The browser has no way to know whether or not that particular content should be there and whether or not it should be loaded. CSP changes that and allows the host to define a whitelist of sources that the browser is allowed to load content from. I wrote a blog covering CSP in much more detail, Content Security Policy - An Introduction, and that will make a great starting point if you need to know a little bit more about CSP before continuing. What I'm going to do in this blog is look at how we can use CSP to block malicious adverts from ever being loaded into our webpages.
What do injected adverts look like?
To show you a mild example of just what ad-injectors can do to one of your webpages, take a look at these screenshots of the BBC and Amazon websites with some malicious adverts present.
These examples aren't too bad and don't intrude as much as they could but they are being injected into the page by malware on the computer. Not only do they detract from the genuine content being served on the page, they are very talkative and induce a hefty amount of load on the network too. Worst of all, all of this is happening so that the organisation who made this malware can make some money off your back. They won't even care about taking prime position and pushing your content below the fold or taking up most of the real estate when the page loads either.
This can give users a really bad impression of your site and it wasn't even your fault. If a user is visiting your page and isn't aware that they have been infected with ad-injecting malware they aren't likely going to realise that these adverts weren't placed there by you. Having to dig through these advert riddled pages to find the genuine content is a real pain and seriously hampers the user experience. Fortunately, using CSP, there is something that we can do about it.
CSP isn't all about anti-XSS
A lot of the time when I see CSP mentioned online it's talked about as an effective countermeasure to Cross Site Scripting (XSS). Whilst this is true and I use CSP for exactly the same thing myself, it takes the incredibly powerful features of CSP and reduces them down to just a subset of what it is capable of. XSS is a hugely prevalent threat online and I can see the attraction of being able to remedy it with CSP, but we mustn't lose sight of what else CSP can offer us. CSP can quite easily rid us of the nasty side effects of a dose of ad-injecting malware that you saw in the screenshots above.
Defending Amazon
Without any administrative control over the Amazon website I don't have the power to implement and deliver a CSP from their end. To get around that little issue, I used the Fiddler web debugger and proxy tool to intercept my own network traffic.
Once Fiddler is installed and ready to go, you can use Fiddler Script to make changes to outbound requests and inbound responses on the fly. It's a very handy and powerful feature and will allow me to resolve the lack of a CSP on Amazon's site.
You can either download their editor or if you want, you can manually edit the file using a text editor of your choice. I'm using Notepad++ and the file is located in C:\Users\*username*\Documents\Fiddler2\Scripts\CustomRules.js
.
I'm going to use the OnPeekAtResponseHeaders()
method which is what Fiddler calls when it intercepts the response headers on the way back from the server and before they are sent on to the client. This is exactly where we'd need to inject our own CSP header for it to be effective.
The policy took a little bit of editing to get right but a simple process of trial and error should quickly have a workable policy up and running. Start off with something basic and then examine the console in the browser to see what legitimate content sources you need to add. I started off with:
oSession.oResponse["Content-Security-Policy"] = "default-src 'self'";
That will prevent the browser from loading any content other than content from the current domain, amazon.com in this case. This resulted in a lot of CSP violations, which is to be expected, and totally broke the page as no assets were being loaded at all! Having a quick scroll through the console you can see that there are some legitimate sources that the page loads content from. You can safely add these to the policy.
From this we can modify the policy to include the domains that look legitimate and leave out the domains that look a little more suspicious.
oSession.oResponse["Content-Security-Policy"] = "default-src 'self' 'unsafe-inline' 'unsafe-eval' *.amazon.com *.images-amazon.com *.ssl-images-amazon.com *.amazon-adsystem.com *.cloudfront.net data:";
With the policy updated and the file saved, Fiddler will now start applying the new rules to our traffic. If we reload the page you can see that the malicious adverts have been stripped out!
To confirm this, you can add a report-uri to the policy and check your Live view over on https://report-uri.io to see the violations coming in. You can read more on my CSP and HPKP violation reporting service here.
In the image you can see CSP violations that are a result of some rogue scripts being blocked from some nasty domains that certainly aren't under the control of Amazon! Now that this content is blocked the user will receive a much better browsing experience. The page loads faster, there aren't any adverts cluttering up the UI and there is nothing interfering with the search results and injecting their own ads. Your average user really isn't going to understand that these adverts are from malicious software on their own computer and not from Amazon themselves. After all, these adverts are on the Amazon website!
Conclusion
With just a few minutes work and the inclusion of a simple CSP response header we have managed to successfully combat 2 types of ad injecting malware that were present on the VM I was using. Admittedly there will be a little more work implementing and testing your own CSP but this demonstrates just how easy it can be to counter some pretty nasty threats your users face and how CSP is useful for much more than just defending against XSS attacks. The stream of inbound reports from such a policy is really insightful and shows just how many of your users would have been seeing malicious adverts on your site without this policy in place. Would these users have thought those were your adverts? Were those adverts even appropriate or could they have hosted or linked to further malicious content? We can't really know but the point here is that if you didn't put it in your page, you don't want it in your page and that's exactly what CSP is here to take care of. Coupled with violation reporting from https://report-uri.io you can have a robust defense and greater insight into such threats in real-time.