Master

A policy that cannot be loosened

My CSP worked in dev but I was tempted to add unsafe-inline for prod. A nonce-based policy forces you to keep it strict, so the loosening never happens.

What you will see

Content-Security-Policy: script-src 'self' 'nonce-abc123'

About 1 min of reading

Try It

Deploy report-only, read it, then enforce.

1

Ship the report-only policy and collect what it would block.

curl -sI https://yoursite/ | grep -i report-only

Before you run it, say out loud what it will print. Then open the answer.

What it prints
Content-Security-Policy-Report-Only: script-src 'self' 'nonce-abc123'; report-to=csp
2

After reports are clean, switch to the enforcing header.

curl -sI https://yoursite/ | grep -i '^content-security-policy:'

Before you run it, say out loud what it will print. Then open the answer.

What it prints
Content-Security-Policy: script-src 'self' 'nonce-abc123'
Never add 'unsafe-inline' or 'unsafe-eval' to make a CSP pass. Those flags re-open exactly what CSP blocks. If a needed source is missing, add that source by name or nonce, not the wildcard.

Data Flow

A nonce or hash CSP makes strictness the only option; deploy report-only first to learn the real sources, then enforce the strict policy.
1 Fresh nonce per response
↓
2 Name your inline exactly
↓
3 Report-only finds breaks
↓
4 Then enforce strict
Why this works
Strict by construction

A nonce or hash policy makes strictness the only workable option: to allow your own inline code you name it exactly, so there is no unsafe-inline to reach for. The policy is written so loosening is not a shortcut, it is a rewrite.

Enforce after report

Deploy the report-only version first and read the reports, so you learn every source the page actually needs. Then enforce. Enforcing blind breaks the site the moment a needed source is missing from the list.

Examples

Nonce per response

nonce = secrets.token_hex(16)
csp = "script-src 'self' 'nonce-%s'" % nonce

A fresh random nonce per response, put in the header and on each tag you wrote. A forged tag cannot guess it.

Hash for static

script-src 'sha256-9f2a...'

For a fixed inline block, hash its content and allow that hash. It is strict and stable, no nonce plumbing needed for unchanging code.

Report the breaks

Content-Security-Policy-Report-Only

Ship a report-only CSP first: it logs what it would block without blocking, so you find every violation before you enforce it.

Words this lesson uses

Each one is defined here on this site. Open the entry for the full definition and the other words it points at.

← Auditing a whole app
Previous Lesson
Auditing a whole app
Next Lesson
The standing security pass
The standing security pass →