CDN Content Integrity: SRI, Checksums, and Tamper Detection at Edge
A CDN accelerates delivery, but every edge node is also a potential point of compromise. Without cryptographic integrity guarantees, a single poisoned cache or hijacked origin response can propagate malicious content globally in seconds. This guide covers how to enforce verifiable integrity from origin to browser.
Modern delivery architectures distribute assets across hundreds of points of presence. That scale improves performance metrics but expands the trust boundary. Integrity verification ensures that what the browser executes is bit-for-bit identical to what you published, regardless of what happens in transit or at the edge.
1. Why Integrity Fails at the Edge
CDNs are designed to cache and serve content without revalidating every byte with the origin. This is efficient, but it creates three distinct tampering vectors that traditional TLS does not solve.
TLS protects data in motion between client and edge, and between edge and origin, but it terminates at each hop. Once decrypted at the edge for caching, content sits at rest on shared infrastructure. An attacker who compromises an edge node, poisons cache via a header injection, or intercepts an insecure origin pull can inject persistent malicious payloads that TLS will then faithfully re-encrypt for end users.
Common failure modes include:
- Cache poisoning: Manipulated Host, X-Forwarded-Host, or query parameters cause the edge to cache an attacker-controlled response under a legitimate URL.
- Origin compromise propagation: If your origin is breached, the CDN will cache and amplify the tampered response to all regions before you can purge.
- Supply-chain injection: Third-party scripts for analytics, chat, or ads loaded via CDN become single points of failure. One compromised vendor script executes with full page privileges.
Understanding your CDN architecture overview is critical here. Integrity controls must be layered at the origin, the edge worker, and the browser to provide defense in depth.
2. Subresource Integrity (SRI): Browser-Enforced Guarantees
Subresource Integrity is a W3C standard that lets you pin a cryptographic hash to a resource URL. The browser fetches the resource, hashes it, and blocks execution if the digest mismatches.
| Metric | Edge Processing | Origin Processing | Improvement |
|---|---|---|---|
| Latency (p50) | 8–15 ms | 120–300 ms | 15–20x faster |
| Cache Hit Ratio | 85–95% | N/A | Reduces origin load |
| TLS Handshake | 1–5 ms (nearby PoP) | 50–150 ms | 10–30x faster |
| Bandwidth Cost | $0.01–0.04/GB | $0.05–0.12/GB | 3–5x cheaper |
| Availability | 99.99% (multi-PoP) | 99.9% (single DC) | 10x fewer outages |
SRI is declarative and requires no server changes beyond serving the correct hash in your HTML. It is currently supported for <script> and <link rel="stylesheet"> elements, with growing support for workers and preloaded resources.
How SRI Works
You generate a hash of the file using SHA-256, SHA-384, or SHA-512, base64-encode it, and add it to the integrity attribute. The crossorigin attribute is required for CORS-enabled integrity checks.
<!-- SHA-384 hash generated at build time -->
<script
src="https://cdn.example.com/js/app.9c3f1a.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
crossorigin="anonymous"
referrerpolicy="no-referrer">
</script>
<link
rel="stylesheet"
href="https://cdn.example.com/css/main.4b2e1d.css"
integrity="sha512-6H8yP3z3m2p1q8a9b7c6d5e4f3g2h1j0k9l8m7n6o5p4q3r2s1t0u9v8w7x6y5z4a3b2c1d0e9f8g7h6=="
crossorigin="anonymous">
Generate hashes in your CI pipeline:
# Generate SRI hash for any file
openssl dgst -sha384 -binary app.9c3f1a.js | openssl base64 -A
# Output: oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC
# Node.js alternative
import { generateSRI } from 'sri-toolbox';
const integrity = await generateSRI(fs.readFileSync('app.js'));
SRI Best Practices
- Prefer SHA-384: It balances security and hash length. SHA-256 is acceptable; SHA-512 is stronger but produces longer attributes.
- Never use SRI on mutable URLs: If
/app.jschanges without a filename change, the hash will break. Use content-hashed filenames likeapp.[hash].js. - Provide multiple hashes: Browsers use the strongest supported algorithm:
integrity="sha256-... sha384-... sha512-..." - Automate, don't hand-edit: Integrate hash generation into Webpack, Vite, or esbuild plugins so HTML is always in sync with assets.
SRI complements performance work. When you tune Core Web Vitals, ensure your SRI generation does not block critical rendering paths—hashes are static and add zero runtime cost.
3. Checksums and Content-Digest at the Edge
SRI protects the browser, but what protects the edge itself? Checksum headers provide transport and at-rest integrity between origin and edge, and between edge and client.
Historically, Content-MD5 was used, but MD5 is cryptographically broken. Modern standards use Content-Digest (RFC 9530) and Repr-Digest, which support SHA-256, SHA-512, and Merkle proofs.
Origin-to-Edge Verification
Configure your origin to emit a digest header for every cacheable response. The edge can then validate the object before caching it:
HTTP/1.1 200 OK
Content-Type: application/javascript
Cache-Control: public, max-age=31536000, immutable
Content-Digest: sha-256=:LCa0a2j/xo/5m0U8HTBBNBNCLXBkg7+g+YpeiGJm564=:
Repr-Digest: sha-256=:LCa0a2j/xo/5m0U8HTBBNBNCLXBkg7+g+YpeiGJm564=:
ETag: "a3f1c9-1714550400"
At the edge, a Cloudflare Worker, Fastly VCL, or AWS Lambda@Edge function can recompute the hash on the fly and compare it to the header. If they diverge, the object is discarded and re-fetched, and an alert is fired. This prevents a compromised origin or a man-in-the-middle on the origin pull from seeding poisoned content into the cache.
Edge-to-Client Verification
Even if the edge cache is valid, network corruption can occur. Enabling Content-Digest on edge responses allows browsers and intermediate proxies to verify payload integrity. While browser enforcement for this header is still evolving, it is already valuable for API consumers, service workers, and native apps that can explicitly check it.
For image optimization pipelines, checksums are essential. Transcoded WebP/AVIF variants are generated at the edge; a checksum ensures the optimization worker did not corrupt the output or serve a truncated file due to memory pressure.
4. Tamper Detection at the Edge: Beyond Hashes
Hashes prove integrity; tamper detection proves authenticity and freshness. At scale, you need to know not just that a file is intact, but that it was published by you and is still current.
Key Mechanisms
1. Asymmetric Signing: Sign critical assets with a private key at build time and publish the public key via DNS (TXT) or a well-known endpoint. Edge workers verify the signature using WebCrypto or VCL before caching. Unlike a hash alone, a signature proves origin authenticity even if an attacker can generate a valid hash for malicious content.
2. Signed Exchanges (SXG) and Subresource Signatures: For high-value assets, consider Signed HTTP Exchanges. The origin produces a signed bundle that the edge can serve without being able to modify it undetectably. The browser validates the signature against your certificate.
3. Anomaly Detection: Integrity is not only cryptographic. Monitor edge logs for sudden changes in content length, content-type, or entropy. A JavaScript file that grows by 3KB overnight or suddenly contains eval(atob( is likely tampered, even if hashes were not checked. Pair this with HTTP/2 and HTTP/3 telemetry to detect downgrade or injection attempts.
// Edge Worker (Cloudflare / Fastly Compute) - validate Content-Digest
export default {
async fetch(request, env) {
const res = await fetch(request);
const digest = res.headers.get('Content-Digest');
if (!digest) return res; // or block if policy requires it
const body = await res.clone().arrayBuffer();
const hash = await crypto.subtle.digest('SHA-256', body);
const b64 = btoa(String.fromCharCode(...new Uint8Array(hash)));
const expected = `sha-256=:${b64}:`;
if (digest !== expected) {
// Do not cache, alert, and fail closed
console.error(`INTEGRITY_MISMATCH ${request.url}`);
return new Response('Integrity check failed', { status: 502 });
}
return res;
}
}
5. Choosing the Right Control
No single mechanism covers all cases. Use this matrix to layer controls based on asset criticality and threat model.
| Method | Where Verified | Protects Against | Overhead | Best For |
|---|---|---|---|---|
| SRI (sha384) | Browser | Edge compromise, cache poisoning, supply-chain | Low | All third-party scripts, critical first-party JS/CSS |
| Content-Digest | Edge & Client | Transit corruption, origin MITM, truncated responses | Low | APIs, images, large assets, origin pulls |
| Asymmetric Signature | Edge (Worker) | Origin breach, malicious cache injection | Medium | High-value JS, config files, signed exchanges |
| CSP + SRI | Browser | Inline injection, unauthorized hosts | Low | Enforcing allow-list with require-sri-for |
| Anomaly Monitoring | SIEM / Edge Logs | Stealth tampering, slow drift | Medium | Detection when crypto checks are bypassed |
6. Operational Playbook
Implementing integrity is a build-system problem as much as a security problem. A manual hash will inevitably drift.
Automate in CI/CD
Generate hashes at build time and inject them into templates. Most modern bundlers support this natively. For example, Webpack's webpack-subresource-integrity plugin or Vite's vite-plugin-sri will emit hashes and update HTML automatically. Store the manifest and fail the build if an asset changes without a hash update.
Enforce with Content Security Policy
Combine SRI with CSP to require integrity for all scripts:
Content-Security-Policy:
default-src 'self';
script-src 'self' https://cdn.example.com;
require-sri-for script style;
report-uri /csp-violation-report
This ensures a developer cannot accidentally add a script without an integrity attribute. Violations are reported to your endpoint for triage.
Handle Failures Gracefully
When SRI fails, the resource is blocked. That is the correct security behavior, but it can break the site. Mitigate with:
- Staged rollouts with content-hashed filenames and atomic HTML deploys.
- Monitoring
securitypolicyviolationevents in the browser and edge mismatch logs. - Fast purge automation: on detection of a mismatch, purge the edge cache globally via API and revert to the last known-good version.
Finally, remember that integrity and performance are not opposing goals. A cache that serves verified, immutable assets with long max-age and correct digests is both faster and safer. The edge can serve stale-while-revalidate with confidence when every response is self-verifying.
Frequently Asked Questions
Can SRI protect against a compromised CDN edge node?
Yes. SRI is verified by the browser, not the CDN. Even if an edge node serves tampered JavaScript or CSS, the browser will block execution if the hash does not match the integrity attribute. It is the last line of defense for third-party assets and should be combined with edge-side checksum validation for defense in depth.
Should I use SRI for first-party assets served through my own CDN?
It is recommended for critical scripts. While you control the origin, SRI still protects against cache poisoning, edge compromise, and build pipeline injection. Automate hash generation in CI/CD to avoid manual errors and use content-hashed filenames so updates do not break integrity.
What is the difference between SRI and checksum headers like Content-Digest?
SRI is a client-side enforcement mechanism using an HTML attribute that the browser checks before execution. Content-Digest and Repr-Digest are transport-level integrity signals validated by browsers, edge workers, or intermediate caches to detect corruption or tampering in transit between origin and edge.
How do I handle SRI when assets are frequently updated?
Use content-hashed filenames (e.g., app.a3f1c9.js) and generate SRI hashes at build time. Integrate with your deployment pipeline so HTML is updated atomically with new hashes. Avoid using SRI with mutable URLs without versioning, and enforce require-sri-for via CSP to prevent omissions.