CSP tells the browser where it is allowed to load scripts, styles, images, and other resources from. A properly configured CSP stops most XSS attacks because even if an attacker injects a malicious script into the page, the browser refuses to execute it if it does not match the policy. CSP is the most effective defense against XSS after input sanitization — and unlike sanitization, it works even against zero-day vulnerabilities.
Basic CSP¶
Content-Security-Policy:
default-src 'self';
script-src 'self' 'nonce-abc123';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
connect-src 'self' https://api.example.com;
frame-ancestors 'none';
Each directive defines allowed sources for a specific content type. default-src 'self' permits only resources from the same origin. script-src with a nonce allows only scripts with a matching nonce attribute. frame-ancestors 'none' prevents embedding the page in an iframe (clickjacking protection).
Nonce-based CSP¶
import secrets
@app.after_request
def add_csp(response):
nonce = secrets.token_urlsafe(32)
response.headers['Content-Security-Policy'] = f"script-src 'self' 'nonce-{nonce}'"
return response
A nonce (number used once) is a random value generated for each request. Each legitimate <script> tag gets a nonce="abc123" attribute and CSP permits only scripts with a matching nonce. An injected script without the correct nonce will not execute. Nonces are more secure than hash-based approaches because they do not require knowing the script content in advance.
Gradual Deployment¶
- Report-Only with a permissive policy — discover what CSP would block
- Analyze reports — identify legitimate sources and inline scripts
- Tighten the policy — remove unnecessary sources
- Switch to enforcement — CSP starts blocking
- Monitor reports — detect new sources and potential attacks
Deploying CSP without a Report-Only phase typically breaks the application. A reporting endpoint (report-uri or report-to) collects information about blocked resources and allows iteratively tightening the policy.
Key Takeaway¶
CSP is the most effective defense against XSS. Start with Report-Only, gradually tighten, and monitor reports. Nonce-based CSP is the recommended approach for modern applications.