Chapter 76: JavaScript in HTML

The src Attribute & Subresource Integrity (SRI)

Defending against third-party CDN supply-chain attacks with cryptographic hash verification and CORS.

LEARNING OBJECTIVES
  • Understand how the browser resolves relative and absolute URLs within the src attribute.
  • Implement Subresource Integrity (integrity="sha384-...") to protect web applications from compromised CDNs and supply-chain attacks.
  • Explain why the crossorigin="anonymous" attribute is mandatory for cross-origin SRI verification.
  • Build robust, fail-safe CDN loading architectures with automated local fallback handling using onerror.
🎬 INTERACTIVE VISUAL PIPELINE Core Architecture Simulation
🌐
1. Input
Directives & Tags
⚙️
2. Parse
Tokenizer & AST
🌳
3. Layout
Box Model & Flow
🎨
4. Render
GPU Paint & Composite
PHASE 1: INPUT & DIRECTIVES
Browser receives declarative markup stream, parsing tag tokens and initializing component state.

📖 The Mental Model & Story (Intuitive Foundation)

Imagine a royal king sending a dispatch to an allied castle via a third-party commercial courier service. The king wants the recipient castle to follow the exact military battle plan contained in the envelope.

However, the third-party courier service could be bribed or intercepted by enemy spies along the road. The spy could open the letter, change the orders to "Surrender all weapons immediately", and reseal the envelope. If the guards at the gate accept the letter at face value, the kingdom falls.

To prevent this, the king stamps the envelope with an unbreakable cryptographic wax seal and gives the allied guards an exact mathematical fingerprint of that seal ahead of time. When the courier arrives, the guards compute the fingerprint of the delivered envelope. If even a single grain of wax is displaced, the guards burn the letter at the gate and sound the alarm.

In web development, this is Subresource Integrity (SRI).

Third-Party CDN Request Pipeline with SRI:
1. Browser requests:  <script src="https://cdn.example.com/lib.js" integrity="sha384-xyz...">
2. CDN returns bytes:  [ console.log("Hacked payload"); ]
3. Browser computes:   SHA-384([bytes]) = "sha384-abc..."
4. Verification Check: "sha384-abc..." === "sha384-xyz..."  ==> MISMATCH!
5. Browser Action:     REFUSE TO EXECUTE. Throw NetworkError. Trigger onerror event.

In 2018, attackers compromised the CDN infrastructure used by British Airways (the famous Magecart attack). By injecting 22 lines of malicious JavaScript into an untrusted third-party script, attackers stole 380,000 credit card records. Had British Airways utilized Subresource Integrity, the browser would have detected the hash mismatch and blocked the script instantly.


Technical Deep Dive & Specifications

The W3C Subresource Integrity (SRI) Specification

The Subresource Integrity (SRI) specification enables user agents to verify that dynamically fetched resources (like scripts and stylesheets) are delivered without unexpected manipulation.

1. The integrity Attribute Structure

The integrity attribute accepts one or more space-separated cryptographic metadata digests:

<script 
  src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js" 
  integrity="sha384-Z6abJ41Fk5UqS1/tT9QeQy6hF2o3f5X4e5Q9Q1d5Zk8gZ7b5B2W0m6H3U8e5Q1d5" 
  crossorigin="anonymous"
  defer>
</script>

Each digest consists of:

  1. Hash Algorithm Prefix: sha256-, sha384-, or sha512- (W3C recommends SHA-384 for an optimal balance of cryptographic strength and calculation performance).
  2. Base64-Encoded Hash Digest: The raw binary cryptographic hash formatted as standard base64.

2. Why crossorigin="anonymous" is Mandatory

For cross-origin resources (e.g., hosted on cdnjs.cloudflare.com when your site is mycompany.com), the browser enforces a strict security constraint:

  • Without CORS: The browser treats the cross-origin response as an opaque response to protect cross-origin user data (preventing unauthorized introspection of cross-site resources).
  • The SRI Dilemma: Calculating a cryptographic hash requires reading raw response bytes. If the browser allowed hashing opaque cross-origin responses, an attacker could deduce sensitive cross-origin data by guessing hashes.
  • The Rule: The browser will refuse to check SRI and will block the script unless the CDN serves appropriate CORS headers (Access-Control-Allow-Origin: *) AND the HTML tag specifies crossorigin="anonymous".
+-----------------------------------------------------------------------------------------+
|                              SRI VERIFICATION LIFECYCLE                                 |
+-----------------------------------------------------------------------------------------+
|  1. Parse <script src="cdn/lib.js" integrity="..." crossorigin="anonymous">             |
|  2. Dispatch HTTP GET with header: `Origin: https://mysite.com`                         |
|  3. Check Response: Does CDN send `Access-Control-Allow-Origin`?                        |
|       [NO]  ──> Abort fetch immediately (CORS failure).                                 |
|       [YES] ──> Read byte stream into buffer.                                           |
|  4. Compute Hash Digest (e.g., SHA-384).                                                |
|  5. Compare Computed Hash vs. `integrity` value.                                        |
|       [MATCH]    ──> Execute JavaScript on Main Thread. Fire `onload` event.            |
|       [MISMATCH] ──> Discard bytes. Log Security Error to Console. Fire `onerror`.      |
+-----------------------------------------------------------------------------------------+

Generating SRI Hashes via CLI

You can generate valid SRI digests using the standard Unix openssl utility:

# Generate SHA-384 SRI digest for a local or downloaded file
openssl dgst -sha384 -binary lodash.min.js | openssl base64 -A | sed 's/^/sha384-/'

Or programmatically in Node.js:

const crypto = require('crypto');
const fs = require('fs');

const fileBuffer = fs.readFileSync('dist/bundle.js');
const hash = crypto.createHash('sha384').update(fileBuffer).digest('base64');
console.log(`integrity="sha384-${hash}"`);

SYS: ACTIVE
HULL: 98%
CORE: STABLE
NET: ONLINE
HTML STARSHIP CODE TERMINAL example.html
LIVE RENDER & DIAGNOSTICS CORE TEMP: 45°C
INSPECTING DOM: VALID
TAGS: SCANNING...

💻 Interactive Code Playground

Starter Code

Line-by-Line Code Breakdown

  • Lines 13–20: Fetches dayjs.min.js from Cloudflare CDN with a valid sha512 hash. When the browser verifies the bytes, onload fires and triggers handleDayjsSuccess().
  • Lines 23–30: Attempts to load the UTC plugin, but specifies an intentional invalid hash (sha512-INVALID_HASH...). The browser computes the real hash, detects the mismatch, blocks execution, and immediately triggers the onerror event.
  • Lines 49–55 (handleUtcTampered): Captures the failure event gracefully, allowing developers to alert monitoring pipelines and dynamically inject a trusted local fallback script.

Expected Browser Render Output


SYS: ACTIVE
HULL: 98%
CORE: STABLE
NET: ONLINE
HTML STARSHIP CODE TERMINAL playground.html
LIVE RENDER & DIAGNOSTICS CORE TEMP: 45°C
INSPECTING DOM: VALID
TAGS: SCANNING...
SRI Security Monitor

[ ✅ Day.js loaded safely! Current Time: 2026-08-21 02:45:00 ]
[ 🛡️ SRI Defense Activated: Tampered script blocked from execution! ]

(DevTools Console Error Output):
Failed to find a valid digest in the 'integrity' attribute for resource 'https://cdnjs.../utc.min.js' with computed SHA-512 integrity '...'. The resource has been blocked.

🏋️ Hands-On Exercise

🎯 The Challenge: Build a Resilient CDN Failover with Cryptographic SRI

You are engineering the checkout infrastructure for a financial portal. You are loading the critical mathematics library decimal.js from a public CDN protected by Subresource Integrity. However, if the CDN undergoes an outage or fails the integrity check, your checkout breaks.

Instructions:

  1. Configure the primary script tag to load decimal.js from a CDN with crossorigin="anonymous" and an integrity hash.
  2. Attach an onerror handler to the script tag.
  3. If the primary CDN fails or triggers an SRI violation, dynamically construct and inject a fallback script pointing to your local server (/vendor/decimal.min.js).
  4. Ensure the fallback script executes safely and logs when failover is complete.

🏁 Starter Code Sandbox

SYS: ACTIVE
HULL: 98%
CORE: STABLE
NET: ONLINE
STARTER CODE SANDBOX exercise.html
LIVE RENDER & DIAGNOSTICS CORE TEMP: 45°C
INSPECTING DOM: VALID
TAGS: SCANNING...

⚠️ Common Pitfalls

  1. Omitting crossorigin="anonymous" on Cross-Origin SRI: If you specify integrity on a script hosted on a remote CDN without adding crossorigin="anonymous", the browser will automatically refuse to check the hash and will block the script from loading entirely.
  2. Using SRI on Dynamic / Rolling Releases: Never apply SRI hashes to URLs pointing to latest or floating versions (e.g. lodash@latest/lodash.min.js). When the CDN provider updates the library version, the hash will change, immediately bricking your entire site. Only use SRI with immutable, pinned semantic versions.
  3. Hash Collision Weakness (MD5 / SHA-1): Never use outdated cryptographic hashes like MD5 or SHA-1 for integrity verification. The WHATWG and W3C specifications strictly support only SHA-256, SHA-384, and SHA-512.

💡 Pro Tips

  1. Automate SRI in CI/CD Bundlers: Integrate plugins like webpack-subresource-integrity or rollup-plugin-sri into your production build pipelines. The build tool calculates exact hashes of all chunked outputs and automatically injects them into your server templates.
  2. Multiple Hashes for Progressive Upgrade: You can specify multiple space-separated hashes in a single integrity attribute (e.g., integrity="sha256-abc... sha384-def..."). The browser will select the most secure algorithm it supports (SHA-384 or SHA-512 over SHA-256).

📌 Key Takeaways

  • Subresource Integrity (SRI) ensures that files fetched from external CDNs match the exact cryptographic digest intended by developers.
  • If an external script is modified (via CDN compromise, MITM attack, or DNS hijacking), the browser blocks execution and fires onerror.
  • The crossorigin="anonymous" attribute is required whenever applying SRI to cross-origin resources to satisfy CORS data isolation rules.
  • Always pin CDN dependencies to fixed versions before generating cryptographic hashes.
  • Build resilient production architectures by attaching onerror failover handlers to recover seamlessly from CDN outages.
  • --
⭐ LEARN: HTML 🌟 ⚔️ QUIZ BATTLE ARENA // ACTIVE
3x
STREAK!
BONUS ACTIVE
COMBO
? Question 1 / 3

What happens when a browser downloads a script where the calculated SHA-384 digest differs from the value in the integrity attribute?

Question 1 / 3 Topic: HTML Fundamentals
00:45 REMAINING
XP REWARD
+250 XP
3x
STREAK!
BONUS ACTIVE
COMBO
? Question 2 / 3

Why must <script integrity="..." src="https://cdn.example.com/lib.js"> also include crossorigin="anonymous"?

Question 2 / 3 Topic: HTML Fundamentals
00:45 REMAINING
XP REWARD
+250 XP
3x
STREAK!
BONUS ACTIVE
COMBO
? Question 3 / 3

Which of the following hash algorithm prefixes is officially valid for Subresource Integrity?

Question 3 / 3 Topic: HTML Fundamentals
00:45 REMAINING
XP REWARD
+250 XP