Content Security Policy: A Practical Guide

On this page
  1. How does CSP blunt XSS?
  2. Nonces vs allowlists
  3. How do you roll out CSP without breaking the site?

A Content Security Policy (CSP) is an HTTP header that tells the browser exactly which scripts, styles, and other resources a page may load or run. Its headline job is defense against cross-site scripting: even if an attacker injects markup, a strict CSP decides whether that markup can actually execute. It is the second layer, after output encoding, that assumes the first will someday fail.

How does CSP blunt XSS?#

Output encoding tries to stop injection; CSP limits the damage when something slips through. A policy that only permits scripts carrying a server-generated nonce means an injected <script> — which cannot know the nonce — simply will not run:

Content-Security-Policy:
  script-src 'nonce-r4Nd0m' 'strict-dynamic';
  object-src 'none';
  base-uri 'none'

'strict-dynamic' lets your nonce-marked scripts load their own dependencies, which is what makes this deployable on real apps. object-src 'none' and base-uri 'none' close common bypass avenues.

Nonces vs allowlists#

Older CSPs listed allowed hostnames, which proved fragile:

ApproachProblem
Host allowlistBypassable via trusted CDNs, JSONP, open redirects
Nonce + strict-dynamicAttacker cannot guess the per-response nonce

The nonce approach — a fresh, unpredictable nonce per response — is dramatically more robust and easier to maintain.

How do you roll out CSP without breaking the site?#

Deploy in report-only mode first:

  1. Send Content-Security-Policy-Report-Only with your intended policy.
  2. Collect violation reports from real traffic.
  3. Fix legitimate scripts the policy would block (add nonces, remove inline handlers).
  4. When reports go quiet, switch to the enforcing header.

CSP is the most valuable of the HTTP security headers. More at the Web Security hub.

Frequently asked questions#

What does a Content Security Policy do?

A CSP is an HTTP response header that tells the browser which sources of scripts, styles, images, and other resources a page is allowed to load or execute. Its main security value is limiting what an injected script can do, turning many cross-site scripting bugs from exploitable into blocked and reportable.

Why are nonce-based policies better than allowlists?

Host allowlists are hard to get right and often bypassable through trusted-but-abusable domains or JSONP endpoints. A nonce-based policy with strict-dynamic marks each legitimate script with a fresh random value the attacker cannot guess, so injected markup cannot execute — a far more robust design that Google’s research recommends.

Sources & further reading