Introduction: What Are CSP Headers and Why They Matter
Content Security Policy (CSP) is a security standard that helps prevent cross-site scripting (XSS), clickjacking, and other code injection attacks. CSP headers allow website administrators to control which resources can be loaded and executed on their pages, creating a crucial defense layer against the most common web vulnerabilities.
Core Concepts of Content Security Policy
CSP Fundamentals
- Policy Delivery: CSP is primarily delivered via HTTP headers or meta tags
- Directives: Rules specifying allowed sources for different resource types
- Source Lists: Origins from which content can be loaded
- Violation Reporting: Mechanism to monitor policy violations
- Levels: CSP has evolved through multiple levels (CSP 1.0, 2.0, 3.0) with increasing capabilities
CSP Implementation Methods
Method | Syntax | Advantages | Disadvantages |
---|---|---|---|
HTTP Header | Content-Security-Policy: directive source-list | Browser processes before page load, more secure | Requires server-side configuration |
Meta Tag | <meta http-equiv="Content-Security-Policy" content="directive source-list"> | Can implement without server access | Processed after HTML parsing begins |
Report-Only Mode | Content-Security-Policy-Report-Only: directive source-list | Tests policy without breaking functionality | Doesn’t actually block violations |
Step-by-Step CSP Implementation Process
- Audit Your Resources: Identify all content sources used by your website
- Create a Baseline Policy: Start with a simple policy covering crucial directives
- Test in Report-Only Mode: Deploy using
Content-Security-Policy-Report-Only
- Analyze Violation Reports: Review reports and adjust policy accordingly
- Gradually Tighten Policy: Incrementally restrict sources and add directives
- Implement Final Policy: Deploy the full CSP header
- Continuous Monitoring: Maintain violation reporting to catch new issues
Key CSP Directives by Category
Script Control Directives
script-src
: Controls allowed sources for JavaScriptscript-src-elem
: Controls inline scripts and script elements (CSP3)script-src-attr
: Controls event handlers and JavaScript in attributes (CSP3)
Content Control Directives
default-src
: Fallback for other fetch directivesstyle-src
: Controls CSS sourcesimg-src
: Controls image sourcesfont-src
: Controls font loading sourcesmedia-src
: Controls audio and video sourcesconnect-src
: Controls fetch, XHR, WebSocket connections
Frame and Object Directives
frame-src
: Controls frames and iframesframe-ancestors
: Controls who can embed your site (replacing X-Frame-Options)object-src
: Controls Flash and other pluginschild-src
: Controls workers and embedded frames (deprecated)
Special Directives
base-uri
: Restricts URLs for<base>
elementsform-action
: Restricts URLs that forms can submit tonavigate-to
: Restricts URLs that can be navigated toupgrade-insecure-requests
: Upgrades HTTP to HTTPSrequire-trusted-types-for
: Requires Trusted Types to prevent DOM-based XSS
Reporting Directives
report-uri
: Specifies endpoint for violation reports (deprecated)report-to
: Modern reporting directive (CSP3)
Source List Keywords & Values
Keyword | Description | Example Usage |
---|---|---|
'none' | Blocks all sources | script-src 'none' |
'self' | Allows same-origin sources | script-src 'self' |
'unsafe-inline' | Allows inline scripts/styles | style-src 'unsafe-inline' |
'unsafe-eval' | Allows eval() and similar | script-src 'unsafe-eval' |
'strict-dynamic' | Propagates trust to scripts loaded by trusted scripts | script-src 'strict-dynamic' |
'nonce-{random}' | Allows resources with matching nonce attribute | script-src 'nonce-abc123' |
'sha256-{hash}' | Allows resources matching specific hash | script-src 'sha256-hash' |
https: | Allows any HTTPS sources | img-src https: |
Domain name | Allows specific domain | script-src example.com |
Common CSP Policy Examples
Basic Restrictive Policy
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; frame-ancestors 'self'; form-action 'self';
Moderate Policy with CDN Support
Content-Security-Policy: default-src 'self'; script-src 'self' cdn.example.com; style-src 'self' cdn.example.com; img-src 'self' data: cdn.example.com; font-src 'self' cdn.example.com; object-src 'none'; frame-ancestors 'self'; report-uri /csp-violation-report;
Enhanced Security with Nonces
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{random-value}'; style-src 'self' 'nonce-{random-value}'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self'; report-uri /csp-violation-report;
Common Challenges and Solutions
Challenge | Solution |
---|---|
Third-party scripts breaking | Use nonces or hashes for trusted scripts; implement 'strict-dynamic' |
Inline styles/scripts | Replace with external files, use nonces, or calculate hashes |
Google Analytics issues | Add www.google-analytics.com , ssl.google-analytics.com to CSP |
Google Fonts problems | Add fonts.googleapis.com and fonts.gstatic.com to appropriate directives |
Reporting endpoint setup | Implement simple server-side logging or use specialized CSP reporting services |
Legacy browser support | Use backward-compatible directives and consider polyfills |
Service worker conflicts | Add relevant domains to connect-src and worker-src |
Best Practices and Practical Tips
Security Enhancement
- Avoid
'unsafe-inline'
and'unsafe-eval'
: These significantly reduce CSP effectiveness - Use nonces or hashes for inline scripts when unavoidable
- Implement
'strict-dynamic'
to simplify policies while maintaining security - Set
object-src 'none'
to prevent plugin-based attacks - Configure
frame-ancestors
to prevent clickjacking - Add
base-uri 'self'
to prevent base URI injection attacks
Implementation Tips
- Start in Report-Only mode to identify potential issues
- Incrementally tighten policies rather than deploying strict rules immediately
- Maintain a reporting endpoint to catch violations in production
- Use specific directives instead of relying on
default-src
- Regularly audit and update your CSP as your site evolves
- Test across browsers to ensure compatibility
- Use automated tools to generate and validate policies
CSP Header Deployment by Web Server
Apache (.htaccess or httpd.conf)
<IfModule mod_headers.c>
Header set Content-Security-Policy "default-src 'self'; script-src 'self';"
</IfModule>
Nginx (nginx.conf)
add_header Content-Security-Policy "default-src 'self'; script-src 'self';";
Express.js
app.use(function(req, res, next) {
res.setHeader('Content-Security-Policy', "default-src 'self'; script-src 'self';");
next();
});
CSP Policy Evaluation Tools
Tool | Purpose | URL |
---|---|---|
CSP Evaluator | Analyzes policy effectiveness | https://csp-evaluator.withgoogle.com/ |
Report URI | CSP reporting service | https://report-uri.com/ |
CSP Scanner | Automated policy scanning | https://cspscanner.com/ |
Security Headers | Tests all security headers | https://securityheaders.com/ |
Mozilla Observatory | Comprehensive security testing | https://observatory.mozilla.org/ |
CSP Levels Comparison
Feature | CSP Level 1 | CSP Level 2 | CSP Level 3 |
---|---|---|---|
Basic directives | Yes | Yes | Yes |
Nonces | No | Yes | Yes |
Hashes | Limited | Yes | Yes |
strict-dynamic | No | No | Yes |
Reporting | report-uri | report-uri | report-to |
Worker controls | child-src | child-src | worker-src |
Granular script control | No | No | script-src-elem /script-src-attr |
Navigation restrictions | No | No | navigate-to |
Trusted Types | No | No | require-trusted-types-for |
Resources for Further Learning
Official Documentation
Tools and Services
Advanced Guides
Remember: A properly implemented CSP is an essential layer in a defense-in-depth security strategy, but it should complement, not replace, other security measures such as input validation, output encoding, and secure coding practices.