A Content Security Policy (CSP) is an HTTP response header that lets website owners control which resources — scripts, styles, images, fonts, frames — the browser is allowed to load. It’s one of the most effective defenses against cross-site scripting (XSS) and data injection attacks.
How CSP works
The server sends a Content-Security-Policy header with a set of directives. Each directive specifies an allowed source list for a particular resource type:
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src *
This policy means:
- By default, only load resources from the same origin
- Scripts can come from the same origin or
cdn.example.com - Styles can be inline or from the same origin
- Images can load from anywhere
If a resource violates the policy, the browser blocks it and logs a violation in the console.
Key directives
default-src: Fallback for all resource types not explicitly specifiedscript-src: Controls JavaScript sources. Blocking inline scripts ('unsafe-inline') is where most XSS protection comes fromstyle-src: Controls CSS sourcesimg-src: Controls image sourcesconnect-src: Controls fetch, XHR, WebSocket, and EventSource targetsframe-src: Controls iframe sourcesfont-src: Controls web font sourcesreport-uri/report-to: Where the browser sends violation reports
Nonces and hashes
Instead of allowing all inline scripts ('unsafe-inline'), you can whitelist specific ones:
- Nonce: Generate a random token per request. Add
nonce="abc123"to the script tag and'nonce-abc123'to the policy. - Hash: Compute the SHA-256 hash of the inline script content and add
'sha256-...'to the policy.
Content-Security-Policy: script-src 'nonce-4AEemGb0xJptoIGFP3Nd'
<script nonce="4AEemGb0xJptoIGFP3Nd">doSomething();</script>
Report-only mode
Use Content-Security-Policy-Report-Only to test a policy without enforcing it. The browser logs violations but still loads the resources. This is essential for rolling out CSP gradually on existing sites without breaking functionality.
Common mistakes
- Setting
'unsafe-inline'and'unsafe-eval'defeats the purpose of CSP - Forgetting
connect-srcblocks your API calls - Overly permissive policies (
default-src *) provide no real protection - Not testing with report-only first, leading to broken pages
Generate CSP headers with the CSP Header Generator and audit your current headers with the Security Headers Checker. For Subresource Integrity on external scripts, use the SRI Hash Generator.