Subresource Integrity (SRI) is a security feature that lets browsers verify that resources fetched from CDNs or third-party origins have not been tampered with. In an era of supply chain attacks — the British Airways Magecart breach, the Polyfill.io compromise, and numerous CDN incidents — SRI provides cryptographic assurance that the resource your page loads is exactly what you intended.
How SRI Works
When you add an integrity attribute to a <script> or <link rel="stylesheet"> tag, the browser computes the hash of the fetched resource and compares it to the attribute value. If they don’t match, the browser refuses to execute or apply the resource.
<script
src="https://cdn.example.com/library.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
crossorigin="anonymous"
></script>
Multiple hashes (comma-separated) allow graceful fallback when multiple versions of a resource are acceptable:
<script
src="https://cdn.example.com/app.js"
integrity="sha384-ABC... sha512-XYZ..."
crossorigin="anonymous"
></script>
The crossorigin="anonymous" attribute is required for SRI on cross-origin resources. Without proper CORS headers, the browser loads the resource in opaque mode and cannot verify its integrity — the resource is silently ignored with no error.
Generating SRI Hashes
You can generate SRI hashes using OpenSSL, online tools, or build-time plugins:
# OpenSSL command
openssl dgst -sha384 -binary file.js | openssl base64 -A
For automation, integrate SRI generation into your build pipeline. Build tool support is mature:
| Tool | Plugin / Config |
|---|---|
| webpack | webpack-subresource-integrity |
| Vite | vite-plugin-sri or built-in via experimental.renderBuiltUrl |
| Next.js | experimental.sri in next.config.js |
| Astro | Built-in integrity prop on asset components |
// Next.js SRI configuration
// next.config.js
module.exports = {
experimental: {
sri: {
hash: "sha384",
},
},
};
Ensure hashes are computed after minification and source map generation — the hash must match the final served content, not the development source.
SRI and CSP Correlation
Content Security Policy and SRI complement each other. CSP restricts which origins can load resources; SRI ensures resources from allowed origins have not been modified. Combined, they provide defense-in-depth for third-party resource loading.
<!-- CSP header -->
Content-Security-Policy:
script-src https://cdn.example.com 'sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC';
report-uri https://reporting.example.com/csp-violations
<!-- HTML with SRI -->
<script
src="https://cdn.example.com/library.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
crossorigin="anonymous"
></script>
Use CSP’s report-uri or report-to directives to monitor SRI violations. A mismatched hash may indicate CDN compromise, a build pipeline issue, or content transformation by middleware.
Monitoring SRI Violations and Advanced Patterns
Listen for error events on elements with integrity attributes, or use the Reporting API to collect SRI violation reports from browsers:
// Client-side SRI violation monitoring
document.querySelectorAll("script[integrity]").forEach((el) => {
el.addEventListener("error", (event) => {
fetch("/api/sri-violation", {
method: "POST",
body: JSON.stringify({
src: el.src,
integrity: el.getAttribute("integrity"),
timestamp: new Date().toISOString(),
}),
});
});
});
CDN providers differ in SRI support. Verify your CDN’s capabilities:
| CDN | SRI Support | Notes |
|---|---|---|
| cdnjs | Full | Hashes provided for all libraries |
| jsDelivr | Full | Hashes in package API responses |
| UNPKG | Via ?meta | Hash available via query parameter |
| Google Hosted Libraries | Partial | Only for supported libraries |
Advanced SRI patterns include dynamic verification for scripts loaded after user interaction, SRI for web workers (new Worker("script.js", { integrity: "..." })), and integrity on import map entries for ES module sharding.
// Dynamic SRI verification for runtime-loaded scripts
async function loadWithIntegrity(url, integrity) {
const response = await fetch(url);
const buffer = await response.arrayBuffer();
const hash = await crypto.subtle.digest("SHA-384", buffer);
const base64 = btoa(String.fromCharCode(...new Uint8Array(hash)));
if (base64 !== integrity.replace("sha384-", "")) {
throw new Error("Integrity check failed");
}
// Execute the script safely
const blob = new Blob([buffer], { type: "text/javascript" });
const blobUrl = URL.createObjectURL(blob);
const script = document.createElement("script");
script.src = blobUrl;
document.body.appendChild(script);
}
Implement a fallback strategy: load from the primary CDN with SRI, and fall back to a self-hosted copy if integrity verification fails. This ensures your application remains functional even if a CDN is compromised or changes its content.
SRI is a critical security control that is simple to implement: generate a hash, add the integrity attribute, configure CORS headers, and automate hash generation in CI. Combined with CSP, it provides robust protection for third-party resource loading. Add SRI to all external resources, automate the process, and monitor for failures proactively.
