Content Security Policy
CSP is a defense-in-depth mechanism for limiting which resources a page can load and which scripts it can execute — even if an attacker manages to inject content.
How CSP is delivered
Via the Content-Security-Policy response header. A meta tag also works but is more limited (no frame-ancestors, can't apply to network responses).
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-rAnd0m';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.example.com;
frame-ancestors 'none';
base-uri 'self';
form-action 'self';
upgrade-insecure-requests;
Core directives
| Directive | Controls |
|---|---|
default-src | Fallback for fetch directives that aren't set. |
script-src | JavaScript sources, inline scripts, and eval. |
style-src | CSS sources and inline styles. |
img-src | Image sources. |
connect-src | fetch, XHR, WebSocket, EventSource targets. |
font-src | Font sources. |
frame-ancestors | Who can <iframe> this page (replaces X-Frame-Options). |
base-uri | Permissible values for <base> — prevents path hijacking. |
form-action | Where forms can be submitted. |
object-src | Plugin content. Best set to 'none'. |
Nonces vs hashes vs strict-dynamic
- Nonce. Server generates a random value per request, places it in the header and on every
<script nonce="…">tag. Only scripts with a matching nonce run. Rotates automatically. - Hash. Pre-compute SHA-256 of static inline scripts and list them in the policy. No server-side rendering needed.
- strict-dynamic. A nonced/hashed script can dynamically load further scripts; those inherit trust. Lets modern bundlers work without listing every CDN.
Roll it out safely
- Send
Content-Security-Policy-Report-Onlywith your draft policy and areport-toendpoint. - Watch the reports for a week. Tighten misses; identify legitimate sources you missed.
- When violations drop to zero, switch to the enforcing header.
- Keep collecting reports — a sudden spike usually means a new third-party script was added without coordination.
!
Avoid 'unsafe-inline' in script-src. It defeats most of CSP's XSS mitigation. Use nonces or hashes instead.