<img height="1" width="1" src="https://www.facebook.com/tr?id=1879927395628828&amp;ev=PageView &amp;noscript=1">

Your [Users’] Browsers, Crypto Mining and $24

 Mar 5, 2018 8:41:25 AM |    Jason White

I've got a bad feeling.png

I wrote a little while back about the AppSec Serenity Prayer and talked about things you can and can’t control in terms of your application security. The recent BrowseAloud incident is a perfect reason to talk about this again and provide some real-world examples of how CSP and SRI could have prevented/mitigated this attack.

What is BrowseAloud, What Happened?

BrowseAloud is a javascript file that, when loaded in your page, “adds speech, reading, and translation to websites facilitating access and participation for people with Dyslexia, Low Literacy, English as a Second Language, and those with mild visual impairments.” (https://www.texthelp.com/en-us/products/browsealoud/)

The file was reportedly hosted on over 4000 web sites and their licensing model forces you to load the file from their hosted site. I assume they use some CORS configuration to enforce where it can/can’t be loaded from … but they cannot actually stop anyone from copying and self-hosting, it’s javascript (but we won’t get distracted with that angle for now).


(from https://www.browsealoud.com/plus/scripts/ba.js)

Also, the script can be accessed (plaintext in transit) from http://www.browsealoud.com/plus/scripts/ba.js, which also means it could be tampered (Man-in-the-Middle attack) on the load from browsealoud.com.

What happened (the short version) is that the script was changed maliciously, inserting a document.write (with js obfuscation … take a look if you like:https://pastebin.com/x772SUQU) which would then inject a monero (cryptocurrency) mining script into everyone’s browser who loaded the BrowseAloud script. The net ‘damage’ was people’s CPUs and network connections were used to mine cryptocurrency for someone else. Javascript is not efficient for this, but the allure of access to browsers for visitors to these 4000+ sites x was apparently enough for the attackers to take the risk on it. The net win for them … $24. It could have been much worse for visitors to some of those sites if they had decided to perform more targeted attacks. Speaking of which ...

What Could go Wrong?

If you host some else’s javascript file in your page/site/application, that amounts to sanctioned Cross-site Scripting (to be blunt). I’m not saying that it is guaranteed to end poorly for you, but you should understand that you just gave carte blanche to all your users’ loaded pages to whomever hosts (or takes over & modifies) that script. You are sanctioning their script to run as if it was from the same origin (read at MDN and Wikipedia if you’d like about Same-origin policy).

But, I know … your job is already hard enough and your boss says your site needs to be 508 compliant, amongst other things. He found a drop-in solution for that … and you would like to still see your family this month. So, you will be hosting the file  … won’t you!?!?!?

What You Can Do

Now that you have no choice but to allow someone to run their javascript on your site, what can you do to protect yourself and your users? 

First, Acknowledge Your Situation

Like in the serenity prayer, previously mentioned it’s important to know the difference between the things you can change and those you can’t. It’s important to be upfront and acknowledge that any data served by your application (where this script is included) can be accessed by this script. This includes username and password if you include this script on a login page.  It can also include any information on a subsequent page. This can all be exfil’d if the script is changed to do so.  Maybe you only serve publicly available static pages. In that case, it’s not as big of a deal. If you have already thought this through (or tried to in the discussion with your boss) … Congratulations, you just did some threat modeling!

Second, Use the Worst-named Flag/Attribute on the Web

Yes, I speak of HttpOnly. What does HttpOnly do? It obviously tells the browser whether or not javascript can access your site’s cookies. It’s a flag you set on cookies (True is good, False is bad).

Ensure your app/framework sets HttpOnly to true on its cookies, especially on those used for authentication/sessions.  Most modern frameworks do this for you, but trust AND verify is the name of the game.


Next, Defend with SRI and CSP

So, now let’s see what SRI and CSP can do for us!

Verify the Integrity of the script.  

Use Sub Resource Integrity (SRI). This will ensure that the script you expect to load is the script you get (pending browser support of course). First, review the script to ensure nothing is hinky. And yes, ‘hinky’ is the technical term! Next, you need to hash the script. You can do this with a tool such as the SRI Hash Generator. You can also do it manually, like this.

$ cat YourFile.js | openssl dgst -sha384 -binary | openssl enc -base64 -A
 The output of the ba.js file with the command above was:

You could also do it for sha256 and sha512 if you want. The result is your page would include something like this (from the SRI Hash Generator tool referenced above):

<script src="https://www.browsealoud.com/plus/scripts/ba.js" integrity="sha256-25QlqDofGxAfNkyL+wwkFrdZTNswCyRUTQYWrZDqnzY= sha384-cnR4/ppFBApTv56lLca18rTXF5kZ7+b6EHiH2ShWfQ0YuRaF5PpL5jr8jBA8IZ98 sha512-8nrsaaJZJxuG9m7IFvne8xnRRT4ZTak3hh6qHx/FcMDDKOej3En8SobZc1/Is0jfrdYN7f9jAk1rjef6Bbhm9A==" crossorigin="anonymous"></script>

Reviewing, hashing and implementing this integrity check ensure that the script you expect is the script that runs in your page. If the hash does not match, the script does not run. Also, this protects you whether you are loading over http or https since we are checking the digest of the file contents.

You can go one step further and use require-sri (more on that below) to force all scripts loaded to use SRI.

Control Inbound Sources and Outbound Connections

Since we are doing what we can, one other thing you *can* (and should) do is implement a Content-Security-Policy. This is a response header that provides directives to the browser, including where scripts can be loaded from and where connections can be made to externally. So, let’s implement script-src, connect-src and some reporting. We’ll assume the domain you are running is https://important-data.com.

  • script-src: your CSP would start with something like:

    Content-Security-Policy: script-src https://important-data.com/scripts/*.js;

  • connect-src: Now we expand the CSP some … it might look like

    Content-Security-Policy: script-src https://important-data.com/scripts/*.js; connect-src https://important-data.com/api/*
  • report-uri: This tells the browser where to report attempted violations (since they occur in the browser and not on requests to your server). There are services you can use for this, but we’ll pretend you run your own at https://important-data.com/csp-reports. So, your CSP now looks like:

    Content-Security-Policy: script-src https://important-data.com/scripts/*.js; connect-src https://important-data.com/api/*; report-uri https://important-data.com/csp-reports

And if you want to enforce SRI as we discussed above …

Content-Security-Policy: script-src https://important-data.com/scripts/*.js; connect-src https://important-data.com/api/*; report-uri https://important-data.com/csp-reports; require-sri-for script

NOTE: require-sri can also be implemented for style (e.g. require-sri-for script style)


Finally, Don’t Let Yourself Be Framed

If your page is embedded in a frame of some sort, these defenses can be undone because your response header may be overridden/ignored. Yes, users *should* notice that the URL is not actually your site, but don’t assume (You know what happens when you assume, right?) that will happen. So, let’s extend that CSP just a little more …

Content-Security-Policy: script-src https://important-data.com/scripts/*.js; connect-src https://important-data.com/api/*; report-uri https://important-data.com/csp-reports; require-sri-for script; frame-ancestors none;

And for good measure, add another header, x-frame-options. That should look like this:

X-Frame-Options: DENY

… or if you have to allow your site/page to be embedded/framed, then be as restrictive as you can with it (and go back to the first point of acknowledging your situation, since you may be open to UI Redressing, aka clickjacking).

Having Done All That …

You are likely much faster than the other person the lion is chasing (as the saying goes). You have just implemented solid defenses potentially self-inflicted XSS (or any XSS really). Having done all that, you can go home, see your family and sleep better … Knowing you have done what you can.


Topics: Security Assessment, Application Security, Information Security, Threat Modeling

Want more of the AsTech Blog? You got it.
Blog subscribers get email updates twice a week.