Web security ·
How SRI hashes are generated client-side
An SRI hash is a cryptographic digest of the exact bytes a CDN will serve, encoded as base64 and prefixed with sha256-, sha384-, or sha512-. Generating it with Web Crypto in the tab means the third-party script never has to be re-uploaded to a hash website for you to lock the integrity attribute.
What problem does Subresource Integrity solve?
CDNs and npm mirrors can be compromised. Your page still tags <script src> at a URL you do not control. SRI makes the browser hash the response and compare it to the integrity attribute. A swapped payload fails closed.
How does Web Crypto produce the integrity string?
Read the file as ArrayBuffer. Call crypto.subtle.digest with SHA-256, SHA-384, or SHA-512. Convert the digest bytes to base64. Prefix sha256- (or the matching algo). That string is the attribute value.
const buf = await file.arrayBuffer();
const digest = await crypto.subtle.digest("SHA-384", buf);
const b64 = btoa(String.fromCharCode(...new Uint8Array(digest)));
const integrity = `sha384-${b64}`;What breaks SRI in production?
Pretty-printed vs minified bytes, UTF-8 BOM, and CDN transcoding (brotli is fine; content mutation is not). Hash the exact bytes that will be served. Recompute when you bump the package.
How is this different from a file checksum page?
Same digest primitive, different encoding and prefix. A SHA-256 checksum tool often prints hex. SRI is base64 with an algorithm label. Both can use Web Crypto or hash-wasm; neither needs a server.
Should you SRI first-party bundles?
Optional. The high-value target is third-party widgets. First-party hashed assets already change on every deploy via filenames. SRI on self-hosted files still detects unexpected mutation on the wire.
Frequently asked questions
Which SRI algorithm should I use?
sha384 or sha512 for new tags. sha256 is widely supported and still specified. Browsers reject the resource if none of the listed digests match.
Does SRI work with CORS?
Cross-origin scripts need CORS (and typically crossorigin="anonymous") so the browser can read bytes to verify. Same-origin scripts do not.
Why generate the hash locally?
The file may be a pre-release bundle. Uploading it to an online hasher shares the source. crypto.subtle.digest runs on an ArrayBuffer you already have.