Sometimes, assets are just loaded from a CDN, because it's convenient. Package creators advertise with a CDN link to show you how easy it is to implement their great library. "Just add this single script tag to the head of your page and you're good to go".
But for the developer, importing a library should be much more than the statement above. At least you:
- make sure the library is well-known
- the link refers to a popular CDN
- know what you're importing
So let's talk a bit about security.
Cross-Site Scripting (XSS)
Companies that take security seriously, already protect their users against cross-site scripting. In a nutshell, with XSS, an attacker injects a malicious script into a trusted website from another location.
Let's say a well-known company loads the popular library jquery.min.js from a trusted CDN cdn.example.com.
Millions of users have a great experience, because using the CDN makes the site so damn fast.
But what if the CDN get's hacked, and the contents of the library go malicious?
Another option for the hacker is changing jquery.min.js to include all the malicious code they want to run on the website. Since they will not use their own server to host the malicious code, there is nothing wrong in the website's perspective. Everything is loaded from a trusted CDN, right?
So now we have a website with millions of users running malicious code from a "valid" library on a "trusted" CDN. Yeah, more protection is needed!
To make sure valid code is executed by the website, Subresource Integrity (SRI) can be used. It basically means that from the original contents of the library, a hash value is calculated, and checked against the pre defined hash.
The script included on the website will now look like this:
<script src="//cdn.example.com/libs/jquery.min.js" integrity="sha384-I6F5OKECLVtK/BL+8iSLDEHowSAfUo76ZL9+kGAgTRdiByINKJaqTPH/QVNS1VDb" crossorigin="anonymous"> </script>
The users browser loads the script from the CDN, and calculates the hash value. If the value does NOT match the value in the integrity-attribute, execution of the code in jquery.min.js is blocked. The crossorigin-attribute enforces a CORS-enabled load. The anonymous value means that the browser should omit any cookies or authentication that the user may have associated with the domain. This prevents cross-origin data leaks, and also makes the request smaller.
All of the above also applies to sites that do not use a CDN. When all assets are loaded from the web server itself, and the web server get's hacked, then there is a similar situation.
That should be HTTPS!!! Although Subresource Integrity works on both HTTP and HTTPS, you should never serve your page over plain HTTP. In plain HTTP, an attacker can see your traffic flow by unencrypted, and can easily modify your HTML by removing the integrity-attribute. Always use HTTPS!
Do you want to test it out yourself, by adding integrity hashes to you assets? You can generate them at srihash.org. The SRI specification can be found at w3.org. And if you are building a GatsbyJS website, check out the gatsby-plugin-sri plugin I've created to generate the hashes automagically for you.