CSP (Content Security Policy) (CSP)
An HTTP response header that controls which resources (scripts, styles, images) a browser is allowed to load. The primary defense against XSS and data injection attacks.
Full Explanation
Content Security Policy is an HTTP header that tells the browser exactly which resources are allowed to load on your page. If an attacker manages to inject a script tag pointing to evil.com, the browser blocks it because evil.com isn't in your CSP. It's the most effective defense against cross-site scripting (XSS) after properly escaping output.
CSP works through directives. Each directive controls a resource type: script-src for JavaScript, style-src for CSS, img-src for images, connect-src for XHR/fetch, font-src for fonts, and so on. The default-src directive acts as a fallback for any directive you don't explicitly set.
For CDNs, CSP has specific implications. Your CSP must whitelist the CDN domains that serve your assets. If you use cdn.example.com for static files, your policy needs img-src cdn.example.com and script-src cdn.example.com. If you switch CDN providers, you need to update your CSP. This is one reason some teams prefer using 'self' with a CDN that serves from the same domain via CNAME.
The tricky part with CDNs is inline scripts. Many CDN features (real user monitoring, bot detection, edge-injected analytics) add inline JavaScript to your pages. strict-dynamic is the modern solution: you add a nonce to your trusted scripts, and the browser automatically trusts any scripts they load, without needing to whitelist specific domains.
Nonces vs hashes: a nonce is a random value generated per response and added to both the CSP header and the script tag. A hash is the SHA-256 of the script content added to the CSP. Nonces are better for dynamic content because you don't need to know the script content ahead of time. But nonces require a unique value per response, which means your CDN can't cache the HTML (or needs to use edge compute to inject nonces). Hashes work with cached responses but break if the script content changes.
Start with report-only mode. The Content-Security-Policy-Report-Only header enforces nothing but sends violation reports to your endpoint. Deploy this first, collect reports for a week, fix violations, then switch to enforcement. This prevents accidentally breaking your site.
CDN edge workers can add or modify CSP headers on the fly. This lets you manage CSP at the edge without changing your origin application. Some CDNs offer CSP management as a built-in feature.
Examples
# Basic CSP header
Content-Security-Policy: default-src 'self'; script-src 'self' cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' cdn.example.com data:;
# Strict CSP with nonces (recommended)
Content-Security-Policy: default-src 'self'; script-src 'nonce-abc123' 'strict-dynamic'; style-src 'self';
# In your HTML
<script nonce="abc123" src="/app.js"></script>
# Report-only mode (deploy this first)
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-reports;
# Nginx: add CSP header
add_header Content-Security-Policy "default-src 'self'; script-src 'self' cdn.example.com; img-src 'self' cdn.example.com;" always;
# Check a site's CSP
curl -sI https://example.com | grep -i content-security-policy
# Common CDN-friendly policy
Content-Security-Policy: default-src 'self'; script-src 'self' 'strict-dynamic' 'nonce-{random}'; style-src 'self' 'unsafe-inline'; img-src 'self' *.cdn.example.com; connect-src 'self' api.example.com; font-src 'self' fonts.googleapis.com;
Frequently Asked Questions
An HTTP response header that controls which resources (scripts, styles, images) a browser is allowed to load. The primary defense against XSS and data injection attacks.
# Basic CSP header
Content-Security-Policy: default-src 'self'; script-src 'self' cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' cdn.example.com data:;
# Strict CSP with nonces (recommended)
Content-Security-Policy: default-src 'self'; script-src 'nonce-abc123' 'strict-dynamic'; style-src 'self';
# In your HTML
<script nonce="abc123" src="/app.js"></script>
# Report-only mode (deploy this first)
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-reports;
# Nginx: add CSP header
add_header Content-Security-Policy "default-src 'self'; script-src 'self' cdn.example.com; img-src 'self' cdn.example.com;" always;
# Check a site's CSP
curl -sI https://example.com | grep -i content-security-policy
# Common CDN-friendly policy
Content-Security-Policy: default-src 'self'; script-src 'self' 'strict-dynamic' 'nonce-{random}'; style-src 'self' 'unsafe-inline'; img-src 'self' *.cdn.example.com; connect-src 'self' api.example.com; font-src 'self' fonts.googleapis.com;
Related CDN concepts include:
- WAF (WAF) — Web Application Firewall. Inspects HTTP requests at the CDN edge and blocks malicious traffic: SQL …