Security Tip: Subresource Integrity
[Tip#14] What is Subresource Integrity and why is it so important for securing your site?
Greetings everyone! I hope you found last week’s In Depth (Rehashing Passwords) interesting, I certainty did as I was digging into Bcrypt and Argon2. We’ve moved on from the passwords theme this week, although the next In Depth may still be related to login forms. (I’ve got a really cool idea for it, which includes an awesome next interactive demo!)
This week I have a tip about Subresource Integrity (SRI), which is a feature that took me a long time to understand fully. In fact, I didn’t really get it until I was doing a hacking workshop with Troy Hunt, who explained the concept. I hope I can channel his teaching skills and impart that knowledge on to you too. 😀
Subresource Integrity (SRI)
According to the MDN Web Docs:
Subresource Integrity (SRI) is a security feature that enables browsers to verify that resources they fetch (for example, from a CDN) are delivered without unexpected manipulation. It works by allowing you to provide a cryptographic hash that a fetched resource must match.
I think that sums it up pretty well. You use SRI to ensure that the resources (scripts, styles, etc) that your site loads from external locations are what you expect them to be.
The vulnerability that SRI solves is someone compromising an external site whose script you load on your website. If someone can modify a third-party script with malware, it’ll be loaded on your site and the malware will run in your user’s browser, allowing all sorts of nefarious activities
.Let’s use the Bootstrap CSS framework as an example. Following their quick start instructions, we install Bootstrap by adding the following script tag
to our page:<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
crossorigin="anonymous"
></script>
The “integrity=
” in the middle is the SRI hash. It is a SHA384 hash representation of the file the browser expects to find at the URL for the resource being loaded.
If the hash doesn’t match the file then the browser will not load it on the page. The website will probably break, but it will refuse to run any malicious code, and from a security point of view, that is significantly better
.How to Generate an SRI Hash
If the third-party resource you are including on your site doesn’t have an SRI hash, you can easily generate one using an online tool.
If we take Alpine.js as an example, their documentation says to install it in production by adding this tag:
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.12.0/dist/cdn.min.js"></script>
But there is no SRI provided by default, and therefore if unpkg.com
is compromised, your site will be too.
Using the SRI Hash tool, we can add hashes into the script include:
<script src="https://cdn.jsdelivr.net/npm/alpinejs@3.12.0/dist/cdn.min.js" integrity="sha384-cNc6Ohk6WSbK+sByRXr9COZWTDVEag1x/Qb7jg15rtdQ4eOqYCfzwQGAxvoh+FQX" crossorigin="anonymous"></script>
That’s all you need to do - there is no work needed by the provider of the resource. The browser itself will do the hashing when the resource is requested, you just need to tell it the hash you expect.
Important: You shouldn’t blindly add SRI hashes to all third-party resources, instead you need to consider if that resource is likely to be changed by the provider or not.
Both the Bootstrap and Alpine resources above are fully versioned, so they shouldn’t change and should have SRI hashes added. On the other hand, scripts includes for things like Analytics or Credit Card processing typically change over time, as their providers optimise them, so you can’t add SRI hashes without it breaking periodically. There are other controls we’ll dive into later for these situations.
Your task now is to go away and audit all of the third-party resources on your site(s). Check if they’ve got SRI hashes, and if not, consider adding them (when safe). Jump into the comments if you need help generating hashes or identifying if a resource is safe to use SRI on!
A couple of examples for you:
Government websites were compromised when a third-party script provided by BrowseAloud was compromised: https://scotthelme.co.uk/protect-site-from-cryptojacking-csp-sri/
Ticketmaster customers had credit cards stolen by Magecart through compromise of a third-party script: https://www.riskiq.com/blog/external-threat-management/magecart-ticketmaster-breach/
Google “Magecart”, you’ll find heaps of examples, as third-party compromise is one of their things.
Check out the fun Troy Hunt is having after having acquired the coinhive.com domain: https://www.troyhunt.com/i-now-own-the-coinhive-domain-heres-how-im-fighting-cryptojacking-and-doing-good-things-with-content-security-policies/
I’ve used a script tag in this example, but CSS tags should also include SRI hashes. CSS can be used for malicious purposes too!
Magecart (and others) purposefully try to compromise third-party scripts for the purpose of getting their malicious code running in the browser. Once the malicious code is there, it’s often used to steal credit card details.
It’s much easier to have a broken site than have your customers credit cards stolen and have to go through sorting out that mess.
Great article, thanks!
I have a few questions.
Is it possible to add SRI for Google fonts?
Is there some way to use SRI when using CSS @font-face?
Also curious if you know how to do it for Fathom Analytics?