Curious TechieDev Toolbox
All Guides/WEB APPLICATION SECURITY10 min read

What is Content Security Policy (CSP) & How Does It Defeat XSS?

Master CSP Level 3: learn directive syntax, strict nonce implementations, hash verification, and how to safely deploy zero-trust headers.

Key Takeaways
  • Content Security Policy (CSP) is an HTTP response header that restricts the sources of executable scripts, stylesheets, fonts, and frames in modern browsers.
  • A strict CSP provides defense-in-depth against Cross-Site Scripting (XSS), data injection, and clickjacking attacks.
  • Essential fetch directives include default-src, script-src, style-src, img-src, connect-src, and frame-ancestors.
  • Modern CSP Level 3 uses cryptographic nonces (`nonce-{random}`) and SHA-256/384 hashes (`sha256-{base64}`) rather than brittle domain whitelists.
  • `Content-Security-Policy-Report-Only` allows testing policies in production without breaking existing user functionality.

1. What is Content Security Policy?

Content Security Policy (CSP) is an HTTP response header (standardized by the W3C) that allows website administrators to declare approved sources of content that browsers are permitted to load and execute.

By restricting where scripts, styles, images, and network calls can originate, CSP serves as the web's most powerful defense against Cross-Site Scripting (XSS) and data exfiltration vulnerabilities.

2. Core Directives Breakdown

DIRECTIVECONTROLSSECURE DEFAULT
default-srcFallback for all unspecified fetch directives'self'
script-srcPermitted JavaScript execution sources'self' 'nonce-...'
style-srcPermitted stylesheet origins and inline styles'self' 'unsafe-inline'
connect-srcAllowed Fetch, XHR, and WebSocket destinations'self' https://api.domain.com
frame-ancestorsDomains permitted to embed this page in <iframe>'none'

3. Nonce vs Hash-based Policies

Legacy CSP relied on domain allowlisting (e.g. script-src https://cdn.example.com). However, modern security research has shown that domain allowlists can frequently be bypassed via open redirects or JSONP endpoints hosted on the allowlisted CDN.

Strict CSP (Level 3) solves this by using per-request cryptographic nonces:

Content-Security-Policy: script-src 'nonce-rAnd0m123' 'strict-dynamic'; object-src 'none';

4. Frame Ancestors vs X-Frame-Options

While X-Frame-Options: DENY is still supported for backwards compatibility, CSP's frame-ancestors directive is the modern standard because it allows fine-grained control over which parent origins can frame your application.

5. Step-by-Step CSP Rollout Plan

Phase 1: Report-Only Mode: Deploy Content-Security-Policy-Report-Only with a report-to endpoint to discover legacy inline scripts without breaking production traffic.
Phase 2: Refactor Inline Handlers: Move inline onclick="..." attributes to external script event listeners.
Phase 3: Enforce Strict Policy: Switch header to Content-Security-Policy with object-src 'none'.