Subresource Integrity (SRI): How It Protects Your Website
Subresource Integrity (SRI) is a security feature that allows browsers to verify that files fetched from external sources, such as CDNs, have not been modified. It uses cryptographic hashes to ensure the integrity of scripts and styles before executing them.
Subresource Integrity (SRI): How It Protects Your Website
Subresource Integrity (SRI) is a security feature that enables browsers to verify that external resources, such as scripts and stylesheets loaded from third-party sources like CDNs, have not been tampered with. It uses cryptographic hashes to ensure that the fetched file matches an expected hash. If the hash does not match, the browser refuses to execute the resource, preventing potential attacks from compromised external sources.
When you load a script from a CDN, you are trusting that the CDN will serve exactly the file you expect. If the CDN is compromised, an attacker could modify the script to steal user data, deface your site, or perform malicious actions. SRI eliminates this trust requirement by cryptographically verifying each resource. To understand SRI properly, it is helpful to be familiar with concepts like web security fundamentals, Content Delivery Networks (CDNs), cryptographic hashing, and security headers.
What Is Subresource Integrity
Subresource Integrity (SRI) is a W3C standard that allows you to specify a cryptographic hash for external resources. The browser downloads the resource, computes its hash, and compares it to the hash you provided. If they match, the resource is executed. If they do not match, the resource is blocked.
- Integrity Attribute: HTML attribute that holds the cryptographic hash of the resource.
- Cross-Origin Protection: Protects against tampering from CDNs, third-party servers, or man-in-the-middle attacks.
- Hash Algorithms: Supports SHA-256, SHA-384, and SHA-512.
- Base64 Encoding: Hashes are encoded in base64 format.
- Subresource Validation: Verifies both scripts and stylesheets.
<!-- Without SRI (vulnerable) -->
<script src="https://cdn.example.com/library.js"></script>
<!-- With SRI (secure) -->
<script src="https://cdn.example.com/library.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
crossorigin="anonymous">
</script>
┌─────────────────────────────────────────────────────────┐
│ SRI Verification Process │
├─────────────────────────────────────────────────────────┤
│ │
│ 1. Browser requests external resource │
│ │ │
│ ▼ │
│ 2. Resource is downloaded from CDN/server │
│ │ │
│ ▼ │
│ 3. Browser computes hash of downloaded content │
│ │ │
│ ▼ │
│ 4. Browser compares computed hash with integrity value │
│ │ │
│ ▼ │
│ 5a. If hashes match: Execute resource │
│ │
│ 5b. If hashes do not match: Block resource and log error│
│ │
└─────────────────────────────────────────────────────────┘
Why Subresource Integrity Matters
SRI addresses a critical security gap in modern web development: the trust placed in third-party CDNs and external servers. Without SRI, you have no guarantee that the script you requested is the one you intended to load.
- CDN Compromise Protection: If a CDN is hacked, SRI prevents malicious modified scripts from executing.
- Man-in-the-Middle Prevention: Even if an attacker intercepts and modifies the response, SRI blocks execution.
- Accidental Modification Detection: SRI catches unintended changes to files on the server.
- Defense in Depth: Adds a layer of security even if other defenses (HTTPS) are compromised.
- Trust Reduction: Reduces reliance on third-party infrastructure security.
- Content Security Policy Enhancement: Works with CSP to restrict script sources.
How SRI Works
SRI uses a simple but effective mechanism to verify external resources. The process involves generating a hash of the file, adding it to the integrity attribute, and letting the browser perform the verification.
// Step 1: Generate the hash of your file
// Command line example
openssl dgst -sha384 -binary library.js | openssl base64 -A
// Output: oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC
// Step 2: Add the hash to your HTML with the integrity attribute
<script src="https://cdn.example.com/library.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
crossorigin="anonymous">
</script>
// Step 3: Browser downloads the file
// Step 4: Browser computes SHA-384 hash of downloaded content
// Step 5: Browser compares computed hash with provided hash
// Step 6: If match, execute; if not, block and report error
SRI Hash Generation Methods
There are several ways to generate SRI hashes. Choose the method that fits best into your development workflow.
# Generate SHA-384 hash
cat library.js | openssl dgst -sha384 -binary | openssl base64 -A
# For multiple files
for file in *.js; do
echo "integrity=\"sha384-$(cat $file | openssl dgst -sha384 -binary | openssl base64 -A)\""
done
# Generate SHA-384 hash
shasum -b -a 384 library.js | awk '{ print $1 }' | xxd -r -p | base64
# For Node.js users (using -p flag)
cat library.js | openssl dgst -sha384 -binary | openssl base64 -A
const crypto = require('crypto');
const fs = require('fs');
function generateSRI(filePath, algorithm = 'sha384') {
const fileBuffer = fs.readFileSync(filePath);
const hash = crypto.createHash(algorithm)
.update(fileBuffer)
.digest('base64');
return `${algorithm}-${hash}`;
}
const integrity = generateSRI('./library.js');
console.log(integrity);
// Output: sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC
# Use https://www.srihash.org/
# Paste your file URL or content
# Get generated integrity hash instantly
# Browser developer tools (SRI Hash Generator extension)
# Available for Chrome and Firefox
SRI Hash Algorithms
SRI supports three hash algorithms: SHA-256, SHA-384, and SHA-512. SHA-384 is the recommended default as it provides strong security with reasonable performance.
| Algorithm | Hash Length | Security Level | Recommendation |
|---|---|---|---|
| SHA-256 | 256 bits (44 chars base64) | 128-bit security | Minimum acceptable |
| SHA-384 | 384 bits (64 chars base64) | 192-bit security | Recommended (best balance) |
| SHA-512 | 512 bits (88 chars base64) | 256-bit security | For high-security applications |
<!-- SHA-256 -->
<script integrity="sha256-..."></script>
<!-- SHA-384 (recommended) -->
<script integrity="sha384-..."></script>
<!-- SHA-512 -->
<script integrity="sha512-..."></script>
<!-- Multiple hashes (fallback) -->
<script integrity="sha384-... sha512-..."></script>
The crossorigin Attribute
When using SRI with external resources, you must also include the crossorigin attribute. This tells the browser to request the resource with CORS enabled, which is required for SRI verification.
<!-- Anonymous mode (sends no credentials) -->
<script src="https://cdn.example.com/library.js"
integrity="sha384-..."
crossorigin="anonymous">
</script>
<!-- Use-credentials mode (sends cookies and certificates) -->
<script src="https://cdn.example.com/library.js"
integrity="sha384-..."
crossorigin="use-credentials">
</script>
<!-- Why crossorigin is needed: -->
<!-- Without crossorigin, the browser cannot access the response body -->
<!-- for integrity verification due to CORS restrictions -->
SRI for Stylesheets
SRI works for both scripts and stylesheets. The same principles apply to CSS files loaded from external sources.
<!-- CSS file with SRI -->
<link rel="stylesheet"
href="https://cdn.example.com/styles.css"
integrity="sha384-XYZ...abc123"
crossorigin="anonymous">
<!-- Bootstrap CSS example -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM"
crossorigin="anonymous">
SRI with Build Tools
Build tools can automate SRI hash generation, making it easy to integrate into your development workflow.
// webpack.config.js
const SriPlugin = require('webpack-subresource-integrity');
module.exports = {
output: {
filename: '[name].[contenthash].js',
crossOriginLoading: 'anonymous'
},
plugins: [
new SriPlugin({
hashFuncNames: ['sha384'],
enabled: process.env.NODE_ENV === 'production'
})
]
};
const gulp = require('gulp');
const sri = require('gulp-sri');
gulp.task('generate-sri', () => {
return gulp.src('./dist/**/*.{js,css}')
.pipe(sri({
algorithms: ['sha384']
}))
.pipe(gulp.dest('./dist'));
});
// rollup.config.js
import sri from '@rollup/plugin-sri';
export default {
input: 'src/index.js',
output: {
dir: 'dist',
format: 'esm'
},
plugins: [
sri({
algorithms: ['sha384']
})
]
};
SRI and Content Security Policy (CSP)
SRI works well with Content Security Policy (CSP). You can use CSP's require-sri-for directive to enforce SRI for all scripts and stylesheets loaded from your site.
# Enforce SRI for all scripts and styles
Content-Security-Policy: require-sri-for script style
# Combined with script-src
Content-Security-Policy: require-sri-for script; script-src 'self' https://cdn.example.com
# This CSP header forces all external scripts to have valid integrity attributes
# If an external script lacks SRI, the browser will block it
Handling SRI When Files Change
When you update a file (for example, upgrading a library version), the SRI hash changes. You must update the integrity attribute in your HTML to match the new file.
// Old version
<script src="https://cdn.example.com/library-v1.0.0.js"
integrity="sha384-oldhash...">
</script>
// After upgrading to v1.1.0
// Generate new hash for the new file
// Update the integrity attribute
<script src="https://cdn.example.com/library-v1.1.0.js"
integrity="sha384-newhash...">
</script>
// Best practice: Use versioned URLs with SRI
// This way, old and new hashes don't conflict
SRI Limitations
While SRI is powerful, it has some limitations that you should be aware of when implementing it.
- No Support for Dynamically Injected Resources: Resources added via JavaScript after page load are not automatically checked for integrity.
- Inline Resources: SRI does not apply to inline scripts or styles. Use CSP for inline content protection.
- Cross-Origin Requirement: Requires CORS headers from the external server.
- Hash Mismatches Break Functionality: If the hash does not match, the resource is blocked, potentially breaking your site.
- No Automatic Updates: When a library updates, you must manually update the integrity hash.
- Browser Support: Older browsers ignore the integrity attribute (graceful degradation).
Common SRI Mistakes to Avoid
Even experienced developers make mistakes when implementing SRI. Being aware of these common pitfalls helps you avoid them.
- Missing crossorigin Attribute: Without crossorigin, SRI fails because the browser cannot access the response body.
- Wrong Hash Algorithm Prefix: The integrity attribute must include the algorithm prefix (sha256-, sha384-, sha512-).
- Whitespace in Hash: The hash must be continuous without spaces or line breaks.
- Using Old Hashes After Updates: Forgetting to update hashes when files change causes resource blocking.
- Not Testing SRI: Always verify that SRI works correctly, especially after file updates.
- Including Non-ASCII Characters: The hash must be base64 encoded without special characters.
- CDN Doesn't Support CORS: SRI requires CORS support from the external server. Not all CDNs provide proper CORS headers.
Testing SRI Implementation
Testing ensures your SRI implementation works correctly and provides the intended protection.
// 1. Browser DevTools Console
// Check for SRI errors
// Look for messages like:
// "Failed to find a valid digest in the 'integrity' attribute for resource"
// 2. Modify the integrity hash intentionally
// Change one character in the hash
// Verify that the resource is blocked (should fail)
// 3. Network tab inspection
// Check that the crossorigin attribute is properly set
// Verify CORS headers from CDN (Access-Control-Allow-Origin)
// 4. Test with missing crossorigin
// Remove crossorigin attribute
// Verify that SRI fails (resource should be blocked)
// 5. Automated testing
// Use tools like SRI Hash Generator browser extension
// Run automated tests to verify all external resources have valid SRI
// Chrome/Edge error
// Failed to find a valid digest in the 'integrity' attribute for resource
// 'https://cdn.example.com/library.js' with computed SHA-384 integrity
// '...'. The resource has been blocked.
// Firefox error
// Integrity attribute verification failed for resource at
// https://cdn.example.com/library.js (sha384-...)
// Safari error
// The integrity of the resource has been modified
SRI Browser Support
SRI is supported in all modern browsers. Older browsers gracefully ignore the integrity attribute.
| Browser | Supported Version | Notes |
|---|---|---|
| Chrome | 45+ | Full support |
| Firefox | 43+ | Full support | Safari | 13+ | Full support |
| Edge | 13+ | Full support |
| Opera | 32+ | Full support |
| IE | None | Ignores integrity attribute (graceful degradation) |
Frequently Asked Questions
- Does SRI work with local files?
SRI is primarily designed for external resources. For same-origin resources, you already control the server, so SRI is less critical. However, it can still be used for defense in depth. - What happens if the integrity hash doesn't match?
The browser blocks the resource from executing and logs an error in the console. The page continues loading without that resource, which may break functionality. - Can I use SRI with dynamic script loading?
Yes, you can set the integrity attribute on dynamically created script elements before adding them to the DOM. - Does SRI protect against CDN downtime?
No. SRI only verifies file integrity, not availability. If the CDN is down, the resource won't load at all. - Should I use SRI for all external resources?
Yes, for any external script or stylesheet that you rely on for security or functionality. The performance impact of hash verification is negligible. - What should I learn next after understanding SRI?
After mastering SRI, explore Content Security Policy (CSP) for comprehensive resource control, CORS for cross-origin security, security headers for additional protection, and HTTPS and SSL/TLS for secure communication.
Conclusion
Subresource Integrity is a critical security feature that protects your website from tampered external resources. By adding a simple integrity attribute to your script and link tags, you ensure that the files your site loads from CDNs and third-party servers are exactly the files you intended to load.
SRI is easy to implement, has negligible performance impact, and provides strong protection against CDN compromises, man-in-the-middle attacks, and accidental file modifications. The only cost is updating integrity hashes when external files change, which can be automated with build tools.
In a world where most websites rely on external libraries and CDNs, SRI should be a standard part of your security toolkit. Combined with HTTPS, CSP, and other security headers, SRI provides defense in depth against a wide range of attacks. Implement SRI today to protect your users and your website.
To deepen your understanding, explore related topics like Content Security Policy (CSP) for resource control, CORS for cross-origin security, security headers for comprehensive protection, and HTTPS and SSL/TLS for secure communication. Together, these skills form a complete foundation for building secure, trustworthy web applications.
