Content Security Policy, or CSP, is a browser security mechanism. A web application delivers rules in an HTTP response header that define which scripts, stylesheets, images, frames and network connections are allowed. An effective CSP can prevent or substantially reduce the impact of cross-site scripting and unauthorized third-party content.
How does Content Security Policy work?
The server sends the Content-Security-Policy header with the HTML response. The browser
evaluates its directives before loading a resource or executing code. If a request does not match the
policy, the browser blocks it and can report a violation. Enforcement therefore occurs on the client
but is controlled by a policy supplied by the server.
CSP is a defense-in-depth measure. The application must still handle user input correctly, encode output for its context and use safe DOM APIs. CSP limits potential damage if malicious content reaches a page despite those primary safeguards.
Which CSP directives are important?
| Directive | Controls |
|---|---|
default-src | Fallback for resource types without a dedicated directive. |
script-src | Sources and execution conditions for JavaScript. |
style-src | External and embedded stylesheets. |
img-src | Image sources, including data URLs where explicitly required. |
connect-src | Destinations for Fetch, XHR, WebSocket and similar connections. |
frame-src | Content that the page itself may load in frames. |
frame-ancestors | Which sites may embed the application; a defense against clickjacking. |
object-src | Plugin content; commonly set to 'none' in a strict policy. |
base-uri | Permitted targets for an HTML base element. |
form-action | Destinations to which forms may submit data. |
Not every directive falls back to default-src. In particular,
frame-ancestors, base-uri and form-action need to be set explicitly
where those restrictions are required.
What does an example CSP look like?
Content-Security-Policy:
default-src 'none';
script-src 'nonce-RANDOM_VALUE' 'strict-dynamic';
style-src 'self';
img-src 'self' https://images.example;
connect-src 'self' https://api.example;
object-src 'none';
base-uri 'self';
frame-ancestors 'none';
form-action 'self';
This simplified example denies resources unless they are explicitly permitted. Scripts require the nonce generated for that response. Images may originate from the same origin and one image host, while API connections may reach the same origin and one API host. Plugin content and framing of the page are disabled. A production policy must be adapted to the application and tested across all important functionality.
What are nonces and hashes?
A nonce is a random, unpredictable value generated by the server for every response. It appears both
in the CSP and in the nonce attribute of authorized script elements. Injected code does not
know the value and is blocked. A nonce must not be static, reused between responses or derived from
attacker-controlled data.
A hash permits a specific inline code block whose cryptographic hash appears in the policy. This works well for static scripts but requires a new hash whenever the code changes. Host allowlists alone are commonly weaker: if an allowed provider is compromised or offers JSONP or user uploads, the trusted domain itself may become a bypass.
How is CSP introduced safely?
- Inventory resources: Document scripts, styles, frames, APIs and genuinely necessary third parties.
- Reduce unsafe patterns: Remove inline handlers,
eval()and unnecessary third-party code before tightening the policy. - Use Report-Only: Collect violations with
Content-Security-Policy-Report-Onlywithout immediately blocking content. - Tighten the policy: Minimize sources and prefer nonces or hashes for scripts.
- Enable enforcement: Test critical user journeys, error pages and infrequent functionality before and after enforcement.
- Operate reporting: Deduplicate violations, consider privacy and investigate new bypasses or configuration errors.
Which mistakes weaken a policy?
'unsafe-inline'generally permits inline code and removes much of a script policy's protection.'unsafe-eval'permits dynamic code execution through functions such aseval().- Wildcards and broad schemes such as
https:trust far more sources than necessary. - Static or predictable nonces can be reused by an attacker.
- A policy delivered only as an HTML
metaelement does not support every directive and applies only from its position in the document. - Report-Only reports violations but does not block them and must not be confused with enforcement.
Which attacks does CSP not prevent?
CSP does not fix broken access control, SQL injection or server-side vulnerabilities. Nor does it stop abuse of permitted application functions. A weak policy can be bypassed, and older browsers do not support every directive equally. CSP is an important additional browser defense, but neither a substitute for secure development nor proof that an application is free from XSS.
Thank you for your feedback! We will review it and optimize this content.