/tutorials/content-security-policy-explained
Content Security Policy Explained
What a CSP header actually restricts, why it matters even on a site with no obvious vulnerabilities, and how to read one without getting lost in the syntax.
6 min read
Run Security HeadersRelated tools
What CSP actually restricts
A Content Security Policy header tells a visitor's browser exactly which sources a page is allowed to load scripts, styles, images and other resources from. Without one, a browser will run any script that ends up in the page's HTML, regardless of where it came from. A well written CSP limits the damage a cross site scripting bug can do, by making the browser refuse to run a malicious script even if an attacker did manage to inject one into the page.
Reading the syntax of a real policy
A moderately strict example policy
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; img-src 'self' data:; style-src 'self' 'unsafe-inline'
- default-src sets the fallback rule for any resource type not given its own specific directive.
- script-src, img-src and style-src override the default for that specific resource type.
- 'self' allows resources from the page's own origin only.
- A named domain such as https://cdn.example.com adds one specific external source as allowed, and nothing outside the listed sources is permitted.
- 'unsafe-inline', when present, allows inline scripts or styles written directly in the HTML, which weakens the policy considerably and is best avoided where practical.
Why this matters even without a known vulnerability
CSP is a defense in depth measure, meaning its entire purpose is to limit the damage from a problem that has not been found yet. A site with no known cross site scripting vulnerability today might still have one introduced in a future update, through a dependency, a third party widget, or a contact form that does not sanitize input as carefully as intended. A solid CSP means that even if such a bug slips through, an attacker still cannot get an arbitrary script to run, because the browser itself refuses to execute anything outside the allowed sources.
Directives worth knowing beyond scripts and styles
- frame-ancestors controls which sites are allowed to embed this page in a frame, which is the modern replacement for the older X-Frame-Options header.
- connect-src restricts which addresses the page's own JavaScript can make requests to, relevant for anything using fetch or a WebSocket connection.
- object-src, often set to 'none', blocks legacy plugin content such as Flash or Java applets almost nobody actually needs any more.
Building a policy gradually rather than all at once
Writing a strict CSP for an existing site that has never had one is rarely a single step, since it usually breaks something the first time it is switched on, an analytics script here, a font loaded from a CDN there. Most browsers support a report only mode, where the policy is evaluated and violations are logged without actually blocking anything, which lets a team work out the real list of legitimate sources before switching on enforcement for real.
Checking your own site
Frabs' Security Headers tool checks whether a Content Security Policy is present at all, alongside the other headers browsers rely on for this kind of protection. If it is missing entirely, that is usually the highest value header to add first, since it is the one most directly aimed at limiting damage from an unknown future bug rather than a specific known issue.
Related tutorials
