Use a nonce for pages your server renders on each request, a hash for static pages, and avoid long host allowlists. MDN calls nonce and hash policies a strict CSP and recommends them over allowlists, which tend to permit more than intended. Start in report-only mode so you see breakage before users do.
The three approaches
Nonce. The server makes a random value for every response, puts it in script-src 'nonce-...' and sets the same value on each script tag you trust. The value must change on every response and be unpredictable. That means templating, not static files.
Hash. You compute a SHA-256, SHA-384 or SHA-512 hash of a script, Base64 encode it, and list it in the policy. External scripts also need an integrity attribute. Any edit to the script means recomputing and redeploying the hash, so this fits static pages.
Host allowlist. You list sites, such as 'self' or *.example.org. MDN warns these are hard to get right and often whitelist unsafe domains. It cites a case where adding one analytics provider meant adding 187 domains.
Which to choose
- Server rendered, dynamic: best fit: Nonce
- Static HTML: best fit: Hash
- Many third party scripts: best fit: Nonce or hash plus
strict-dynamic - Legacy with inline handlers: best fit: Refactor first, then nonce
What strict-dynamic does
A script with a valid nonce or hash may load more scripts without a nonce of their own, and trust passes down the chain. That helps when a trusted loader pulls in dependencies. MDN notes the trade: if trusted scripts build script elements from an XSS source, the policy will not block them.
Directives to include
MDN's strict policy examples add two lines that are easy to forget:
object-src 'none'blocks plugin content.base-uri 'none'stops the base element from changing how relative URLs resolve.
Also consider frame-ancestors 'none' unless your site must be embedded. Avoid 'unsafe-inline'. MDN adds that browsers ignore it when a nonce or hash is present in the same directive.
A rollout plan
- Send
Content-Security-Policy-Report-Onlywith your draft policy. MDN says both headers can be present, one enforcing and one reporting. Report-only cannot be delivered through a meta element. - Set up reporting endpoints and collect violations.
- Replace inline handlers with
addEventListener()and removejavascript:URLs andeval(). - Send the policy on all responses, not just the main document.
- Switch to enforcement once reports go quiet.
What a CSP is not
OWASP says a CSP should not be your primary defence against XSS, since mistakes are easy to make. Keep output encoding and safe DOM APIs in place. MDN also notes that upgrade-insecure-requests does not replace HSTS.
Quick check
Can I reuse the same nonce on every page load?
No. A reused nonce can be learned and abused. It must be new and unpredictable for each response.
Sources
Last reviewed: 19 October 2026.