Content Security Policy (CSP) is an HTTP response header that provides an extra layer of security against common web attacks like Cross-Site Scripting (XSS), clickjacking, and other code injection vulnerabilities. Think of it as a firewall for your browser, dictating exactly what resources are allowed to load and execute.
Why You Absolutely Need CSP
XSS attacks remain a persistent threat. CSP drastically reduces the attack surface by allowing you to define trusted sources for scripts, styles, images, and other resources. By explicitly whitelisting sources, you prevent the browser from loading anything that doesn’t match your policy, effectively neutralizing many XSS attempts.
Core CSP Directives: The Must-Know Arsenal
Here’s a breakdown of the most essential CSP directives, complete with examples and explanations:
-
default-src
: The Fallback Directive-
Purpose: Specifies the default source for all content types when a more specific directive isn’t defined. This is your baseline.
-
Usage:
Content-Security-Policy: default-src 'self';
'self'
: Allows resources from the same origin (scheme + host + port). Crucially important for basic protection.
-
Why it matters: Without
default-src
, the browser’s behavior is unpredictable. Always define it.
-
-
script-src
: Controlling JavaScript Execution-
Purpose: Defines valid sources for JavaScript code. This is where you’ll spend most of your time.
-
Usage:
Content-Security-Policy: script-src 'self' https://cdn.example.com;
'self'
: Allows scripts from your domain.https://cdn.example.com
: Explicitly whitelists scripts from a specific CDN. Always use HTTPS.
-
Advanced Options (Use with Caution):
-
'unsafe-inline'
: Allows inline JavaScript (e.g.,<script>...</script>
). Generally discouraged due to XSS risks. Only use if absolutely necessary and understand the implications. -
'unsafe-eval'
: Allows the use ofeval()
and related functions. Highly discouraged. Opens a massive security hole. Avoid at all costs. -
'nonce-{random-value}'
: Allows specific inline scripts that have a matchingnonce
attribute. Much safer than'unsafe-inline'
.<script nonce="your-random-value"> // Your inline script </script>
Content-Security-Policy: script-src 'nonce-your-random-value';
- The
nonce
value must be cryptographically random and unique for each request. Generate it server-side.
- The
-
'strict-dynamic'
: Allows scripts loaded by trusted scripts to also load scripts. Useful for modern JavaScript frameworks that dynamically load modules. Requires'self'
or a nonce-based'unsafe-inline'
.Content-Security-Policy: script-src 'self' 'strict-dynamic';
-
-
Why it matters: Prevents the browser from executing malicious scripts injected into your page.
-
-
style-src
: Governing CSS Stylesheets-
Purpose: Specifies valid sources for stylesheets.
-
Usage:
Content-Security-Policy: style-src 'self' https://fonts.googleapis.com;
'self'
: Allows stylesheets from your domain.https://fonts.googleapis.com
: Whitelists Google Fonts.
-
Advanced Options (Use with Caution):
'unsafe-inline'
: Allows inline styles (e.g.,<style>...</style>
andstyle
attributes). Discouraged for the same reasons as with scripts.'unsafe-hashes'
: Allows specific inline styles based on their SHA256, SHA384, or SHA512 hash. More secure than'unsafe-inline'
but still complex to manage.
-
Why it matters: Prevents attackers from injecting malicious CSS that could alter your site’s appearance or steal user data.
-
-
img-src
: Controlling Images-
Purpose: Defines valid sources for images.
-
Usage:
Content-Security-Policy: img-src 'self' data: https://images.example.com;
'self'
: Allows images from your domain.data:
: Allows images embedded as data URIs (Base64 encoded). Use sparingly.https://images.example.com
: Whitelists images from a specific image server.
-
Why it matters: Prevents attackers from displaying malicious images or tracking users through image requests.
-
-
font-src
: Specifying Font Sources-
Purpose: Defines valid sources for fonts.
-
Usage:
Content-Security-Policy: font-src 'self' https://fonts.gstatic.com;
'self'
: Allows fonts from your domain.https://fonts.gstatic.com
: Whitelists Google Fonts.
-
Why it matters: Prevents attackers from injecting malicious fonts that could exploit browser vulnerabilities.
-
-
connect-src
: Governing AJAX and WebSockets-
Purpose: Defines valid sources for
XMLHttpRequest
,Fetch API
, WebSockets, and EventSource connections. Critical for modern web applications. -
Usage:
Content-Security-Policy: connect-src 'self' https://api.example.com wss://ws.example.com;
'self'
: Allows connections to your domain.https://api.example.com
: Whitelists connections to a specific API endpoint.wss://ws.example.com
: Whitelists WebSocket connections. Always usewss://
for secure WebSockets.
-
Why it matters: Prevents attackers from making unauthorized requests to external APIs or intercepting sensitive data transmitted over WebSockets.
-
-
frame-src
andchild-src
(Deprecated, but Important History)-
Purpose: Defined valid sources for nested browsing contexts (iframes).
-
frame-src
: Deprecated in favor ofchild-src
. -
child-src
: Replaced byframe-src
,worker-src
, andconnect-src
. -
Usage (for Legacy Browsers):
Content-Security-Policy: frame-src 'self' https://youtube.com;
-
Modern Usage: Use
frame-src
for iframes,worker-src
for web workers, andconnect-src
for AJAX/WebSockets. -
Why it matters: Prevents clickjacking attacks and restricts the content that can be embedded in your site.
-
-
worker-src
: Controlling Web Workers-
Purpose: Defines valid sources for web worker scripts.
-
Usage:
Content-Security-Policy: worker-src 'self' blob:;
'self'
: Allows web workers from your domain.blob:
: Allows web workers created fromBlob
URLs.
-
Why it matters: Prevents attackers from running malicious code in background threads.
-
-
object-src
: Governing Plugins (Deprecated, but Important)**-
Purpose: Defines valid sources for plugins like Flash and Java applets. Largely irrelevant today as these technologies are obsolete.
-
Usage:
Content-Security-Policy: object-src 'none';
'none'
: Recommended. Disables all plugins.
-
Why it matters: Plugins are a major security risk. Disable them unless you have a very specific reason to use them.
-
-
base-uri
: Restricting<base>
Tag-
Purpose: Defines valid URLs that can be used in a
<base>
element. -
Usage:
Content-Security-Policy: base-uri 'self';
'self'
: Allows<base>
tags that point to your domain.
-
Why it matters: Prevents attackers from redirecting relative URLs to malicious sites.
-
-
form-action
: Controlling Form Submissions-
Purpose: Defines valid URLs that can be used as the
action
attribute of a<form>
element. -
Usage:
Content-Security-Policy: form-action 'self' https://secure.example.com;
'self'
: Allows form submissions to your domain.https://secure.example.com
: Whitelists form submissions to a specific secure endpoint.
-
Why it matters: Prevents attackers from redirecting form submissions to malicious sites to steal user data.
-
-
upgrade-insecure-requests
: Enforcing HTTPS-
Purpose: Instructs the browser to automatically upgrade all insecure HTTP URLs to HTTPS.
-
Usage:
Content-Security-Policy: upgrade-insecure-requests;
-
Why it matters: Ensures that all communication with your site is encrypted, protecting user data from eavesdropping. Essential for HTTPS-only sites.
-
-
block-all-mixed-content
: Blocking Mixed Content-
Purpose: Prevents the browser from loading any HTTP resources on an HTTPS page.
-
Usage:
Content-Security-Policy: block-all-mixed-content;
-
Why it matters: Prevents man-in-the-middle attacks that could compromise the security of your HTTPS site.
-
-
report-uri
(Deprecated)-
Purpose: Specifies a URL where the browser should send CSP violation reports.
-
Usage (Deprecated):
Content-Security-Policy: report-uri /csp-report-endpoint;
-
Why it’s deprecated: Replaced by
report-to
.
-
-
report-to
: Modern Reporting Mechanism-
Purpose: Specifies a named endpoint (defined in a
Report-To
header) where the browser should send CSP violation reports. The modern way to handle CSP reporting. -
Usage:
Report-To: { "group": "csp-endpoint", "max_age": 31536000, "endpoints": [{"url": "https://example.com/csp-report-endpoint"}] } Content-Security-Policy: report-to csp-endpoint;
Report-To
: Defines the reporting endpoint.group
: A name for the endpoint.max_age
: How long the browser should cache the endpoint configuration (in seconds).endpoints
: An array of URLs where reports should be sent.
Content-Security-Policy: report-to csp-endpoint;
: Tells the browser to use thecsp-endpoint
defined in theReport-To
header.
-
Why it matters: Allows you to monitor CSP violations and identify potential security issues.
-
CSP in Report-Only Mode
-
Header:
Content-Security-Policy-Report-Only
-
Purpose: Allows you to test your CSP without actually blocking any resources. Violations are reported to the
report-uri
orreport-to
endpoint, but the browser still loads the resources. -
Usage:
Content-Security-Policy-Report-Only: default-src 'self'; report-to csp-endpoint;
-
Why it matters: Essential for testing and refining your CSP before enforcing it in production.
Best Practices: The Path to CSP Mastery
- Start with
default-src 'self'
: This is your foundation. - Use Report-Only Mode: Test your CSP thoroughly before enforcing it.
- Monitor CSP Reports: Use
report-to
to identify violations and refine your policy. - Avoid
'unsafe-inline'
and'unsafe-eval'
: These are security risks. Use nonces or hashes instead. - Be Specific: Whitelist only the resources you need. Avoid wildcarding.
- Use HTTPS: Always use HTTPS for all resources.
- Automate CSP Generation: Use a tool or library to generate your CSP dynamically.
- Regularly Review and Update: CSP is not a set-it-and-forget-it solution. Review and update your policy as your application evolves.
Example CSP Header: A Solid Starting Point
Content-Security-Policy:
default-src 'self';
script-src 'self' https://cdn.jsdelivr.net 'nonce-{random-nonce}' 'strict-dynamic';
style-src 'self' https://fonts.googleapis.com 'unsafe-inline';
img-src 'self' data: https://images.example.com;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self' https://api.example.com wss://ws.example.com;
frame-src 'self' https://youtube.com;
object-src 'none';
base-uri 'self';
form-action 'self' https://secure.example.com;
upgrade-insecure-requests;
block-all-mixed-content;
report-to csp-endpoint;
Remember to replace {random-nonce}
with a cryptographically random value generated server-side for each request.
Conclusion: Embrace CSP, Secure Your Site
CSP is a powerful tool that can significantly improve the security of your website. By understanding the core directives and following best practices, you can create a robust CSP that protects your users from a wide range of attacks. Embrace CSP, and make your website a safer place.