Content-Security-Policy
Learn how Content Security Policy (CSP) protects your website from XSS attacks and other injection vulnerabilities.
Content Security Policy (CSP) is one of the most powerful security mechanisms available to web developers today. This comprehensive guide will walk you through everything you need to know about implementing CSP to protect your website from cross-site scripting (XSS) attacks and other code injection vulnerabilities.
What is Content Security Policy?#
Content Security Policy (CSP) is one of the most powerful security mechanisms available to web developers. It is a HTTP response header that tells browsers which content sources are permitted to load on your page. CSP works by defining a whitelist of approved origins for scripts, stylesheets, images, fonts, and other resource types. Any resource not matching the policy is blocked by the browser, preventing Cross-Site Scripting (XSS), clickjacking, and other code injection attacks.
- Prevents execution of unauthorized inline scripts and eval-based code
- Restricts which domains can serve scripts, styles, images, and other resources
- Blocks mixed content by enforcing HTTPS for all resource loads
- Provides reporting capabilities to detect policy violations in production
CSP is not a replacement for proper input validation and output encoding. It serves as a strong second line of defense. Even if an XSS vulnerability exists in your code, a properly configured CSP can prevent the injected script from executing.
Why CSP Matters#
Cross-Site Scripting (XSS) consistently ranks among the most common web application vulnerabilities. Traditional defenses like input validation and output encoding are essential but not foolproof. A single missed encoding in a complex application can lead to a full compromise. CSP addresses this by enforcing security at the browser level, providing a safety net that catches attacks even when application-level defenses fail.
- XSS is the most common web vulnerability according to OWASP Top 10
- A single XSS vulnerability can lead to session hijacking, data theft, or account takeover
- CSP reduces the impact of XSS by preventing unauthorized script execution
- CSP reporting helps security teams identify and fix vulnerabilities proactively
Understanding CSP Directives#
CSP policies are composed of directives that control specific resource types. Each directive specifies which sources are allowed for that resource type. The default-src directive serves as a fallback for any resource type that does not have its own directive specified.
- default-src sets the fallback policy for all resource types not explicitly defined
- script-src controls JavaScript execution, the most critical directive for XSS prevention
- style-src controls which stylesheets can be applied to the page
- img-src, font-src, connect-src, media-src each control their respective resource types
- frame-ancestors replaces X-Frame-Options for clickjacking protection
# Anatomy of a CSP header
Content-Security-Policy:
default-src 'self'; # Fallback: only same-origin
script-src 'self' 'nonce-abc123'; # Scripts: same-origin + nonce
style-src 'self' 'unsafe-inline'; # Styles: allow inline CSS
img-src 'self' data: https:; # Images: self, data URIs, HTTPS
connect-src 'self' api.example.com; # XHR/Fetch: self + API
frame-ancestors 'self'; # Who can frame this pageImplementation Strategy#
Deploying CSP requires a careful, phased approach. Starting with a report-only policy allows you to identify what your application loads without breaking anything. Once you have a clear picture of your resource loading patterns, you can create and enforce a production policy.
- Start with Content-Security-Policy-Report-Only to monitor without blocking
- Use a reporting endpoint to collect violation reports and identify necessary sources
- Gradually tighten the policy by removing overly broad sources
- Avoid 'unsafe-inline' and 'unsafe-eval' whenever possible as they weaken CSP significantly
- Use nonces or hashes for inline scripts instead of 'unsafe-inline'
Deploying a strict CSP without testing can break your application. Third-party widgets, analytics scripts, and ad networks often require specific CSP directives. Always start in report-only mode and analyze the violations before enforcing.
Server Configuration Examples#
Here is how to configure CSP in common web servers and frameworks. Remember that CSP policies can be complex, so test thoroughly in report-only mode first.
# Apache (.htaccess)
Header always set Content-Security-Policy "\
default-src 'self'; \
script-src 'self'; \
style-src 'self' 'unsafe-inline'; \
img-src 'self' data:; \
font-src 'self'; \
connect-src 'self'"
# Nginx
add_header Content-Security-Policy
"default-src 'self';
script-src 'self';
style-src 'self' 'unsafe-inline';
img-src 'self' data:;
connect-src 'self'" always;
# Node.js / Express (using helmet)
const helmet = require('helmet');
app.use(helmet.contentSecurityPolicy({
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"],
imgSrc: ["'self'", "data:"],
}
}));CSP Reporting and Monitoring#
CSP includes built-in reporting capabilities that send violation reports to a URL you specify. This is invaluable for both initial deployment and ongoing security monitoring. Reports include details about what was blocked, which page it occurred on, and what the violating resource was.
- Use report-uri or report-to directives to specify your reporting endpoint
- Violation reports include the blocked URI, violated directive, and document URI
- Monitor reports to detect attempted XSS attacks in production
- Use reports to identify legitimate resources that need to be added to the policy
- Third party services like report-uri.com can aggregate and analyze CSP reports
# CSP with reporting
Content-Security-Policy: default-src 'self'; report-uri /csp-report
# Report-only mode for testing
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-reportBest Practices and Common Mistakes#
Effective CSP implementation requires understanding common pitfalls and following established best practices. Here are the key recommendations for a strong Content Security Policy.
- Never use 'unsafe-inline' and 'unsafe-eval' together as this effectively disables CSP for scripts
- Use nonce-based or hash-based policies instead of 'unsafe-inline' for inline scripts
- Keep your policy as restrictive as possible while maintaining functionality
- Use frame-ancestors in CSP instead of the deprecated X-Frame-Options header
- Regularly review and update your policy as your application evolves
- Test your CSP with tools like Google's CSP Evaluator before deployment
Setting script-src to 'unsafe-inline' 'unsafe-eval' provides almost no XSS protection. Using wildcard sources like *.googleapis.com can be exploited through JSONP endpoints. Always be as specific as possible with your allowed sources.
Implementation Examples#
Basic CSP Policy
Content-Security-Policy: default-src 'self'This basic policy only allows resources from the same origin as your website. It's a good starting point that provides significant security improvements with minimal risk of breaking functionality.
Explanation: The 'self' keyword refers to the same scheme, host, and port as the document. This means if your site is https://example.com, only resources from https://example.com will be allowed.
Intermediate CSP Policy
Content-Security-Policy: default-src 'self'; script-src 'self' https://apis.google.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:This policy provides more granular control by specifying different rules for different resource types. It allows Google APIs for scripts, inline styles, and images from HTTPS sources.
Explanation: This configuration is common for websites that use external APIs or CDNs. The 'unsafe-inline' for styles is often necessary for CSS frameworks, though it should be avoided when possible.
Strict CSP Policy
Content-Security-Policy: default-src 'none'; script-src 'self' 'nonce-{random}'; style-src 'self' 'nonce-{random}'; img-src 'self' data:; connect-src 'self'A very restrictive policy that uses nonces for inline scripts and styles. This provides maximum security but requires more careful implementation.
Explanation: Using nonces (cryptographically secure random values) allows you to permit specific inline scripts while blocking all others. This is the most secure approach but requires server-side implementation.
Key Directives#
default-src
Serves as a fallback for other resource types when they don't have policies of their own
default-src 'self'script-src
Controls which JavaScript sources are allowed to execute
script-src 'self' https://trusted-cdn.comstyle-src
Controls which CSS stylesheets can be applied
style-src 'self' 'unsafe-inline'img-src
Controls which image sources can be loaded
img-src 'self' data: https:connect-src
Controls which servers can be contacted via AJAX, WebSocket, and EventSource
connect-src 'self' https://api.example.comfont-src
Controls which font sources can be loaded
font-src 'self' https://fonts.googleapis.comobject-src
Controls which plugin sources can be loaded (Flash, etc.)
object-src 'none'media-src
Controls which audio and video sources can be loaded
media-src 'self' https://videos.example.comReferences#
Test Your Content-Security-Policy Configuration
Scan your site to check if Content-Security-Policy is properly configured.