🚀AdvancedSecurity
Subresource Integrity (SRI)
Protect your site from compromised CDN resources by using SRI hashes on <script> and <link> tags to verify file integrity before execution.
Overview
Subresource Integrity (SRI) is a security feature that allows browsers to verify that resources fetched from external servers (CDNs, third-party libraries) have not been tampered with. You provide a cryptographic hash of the expected file in the `integrity` attribute of `<script>` or `<link>` tags. If the fetched file's hash doesn't match, the browser refuses to execute or apply it.
This protects against supply chain attacks where an attacker compromises a CDN and injects malicious code into a JavaScript library or CSS file that thousands of sites load. Without SRI, your site silently loads and executes whatever the CDN returns SRI makes tampering detectable.
SRI works by computing a base64-encoded SHA hash (sha256, sha384, or sha512) of the expected file content and embedding it in the HTML. The browser recomputes the hash after download and blocks the resource if they don't match.
Key Points
- •Add `integrity="sha384-<hash>"` to `<script>` or `<link rel="stylesheet">` tags for external resources
- •Generate the hash with: `openssl dgst -sha384 -binary file.js | openssl base64 -A`
- •Also add `crossorigin="anonymous"` when using SRI required for cross-origin resources
- •Multiple hashes can be provided space-separated for backward compatibility when rolling out new versions
- •SRI only works for resources served with CORS headers same-origin resources don't need it
- •The `crossorigin` attribute triggers a CORS request, enabling the browser to read the response for hashing
- •SRI does not work with dynamic resources (URLs with query strings that change content)
Examples
SRI on a CDN-hosted script and stylesheet
<!-- Script with SRI hash browser refuses to run if hash does not match -->
<script
src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"
integrity="sha384-wFJSCmHCr28FqYzONpFSDJMLs5lMmIcMoNZ3sMkSU5MHZH9EqIHKUSVtGgCgI7J"
crossorigin="anonymous"
></script>
<!-- Stylesheet with SRI hash -->
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM"
crossorigin="anonymous"
/>Always get SRI hashes from the official library documentation or generate them yourself.
Generating an SRI hash
<!-- Method 1: srihash.org website paste URL, get integrity value -->
<!-- Method 2: Command line -->
<!-- openssl dgst -sha384 -binary lodash.min.js | openssl base64 -A -->
<!-- Method 3: Node.js -->
const crypto = require('crypto');
const fs = require('fs');
const hash = crypto.createHash('sha384')
.update(fs.readFileSync('lodash.min.js'))
.digest('base64');
console.log(`sha384-${hash}`);
<!-- Method 4: Browser DevTools Console -->
async function computeSRI(url) {
const response = await fetch(url);
const buffer = await response.arrayBuffer();
const hashBuffer = await crypto.subtle.digest('SHA-384', buffer);
const base64 = btoa(String.fromCharCode(...new Uint8Array(hashBuffer)));
return `sha384-${base64}`;
}Use sha384 or sha512 sha256 is acceptable but the others provide stronger security.
Multiple hashes and error fallback
<!-- Multiple hashes for version transition browser accepts if ANY hash matches -->
<script
src="https://cdn.example.com/lib.min.js"
integrity="sha384-hashForV1 sha384-hashForV2"
crossorigin="anonymous"
></script>
<!-- Fallback: if SRI check fails, onerror fires -->
<script
src="https://cdn.example.com/lib.min.js"
integrity="sha384-ABC123..."
crossorigin="anonymous"
onerror="loadLocalFallback()"
></script>
<script>
function loadLocalFallback() {
const script = document.createElement('script');
script.src = '/local/lib.min.js';
document.head.appendChild(script);
}
</script>An SRI failure fires the onerror event use this to load a local fallback copy.
Common Mistakes
- Forgetting `crossorigin="anonymous"` alongside the integrity attribute SRI on cross-origin resources requires a CORS request
- Using SRI on dynamically built URLs (with cache-busting query strings) the hash must match the exact bytes
- Computing the hash from a minified version but linking to the unminified version the hash must match the exact file served
Note
Use the CSP header `require-sri-for script style` to enforce that ALL scripts and styles on your page have SRI hashes.
Exercises
Write HTML to solve each exercise. Use Preview to see it render in a live iframe, then mark as done.
Loading editor…
Completed: 0 / 5 exercises
Knowledge Check
Question 1 of 4