Content Security Policy Guide
Content Security Policy (CSP) Guide
CSP is your first line of defense against XSS attacks. Learn how to implement it correctly.
What is CSP?
Content Security Policy is an HTTP header that tells browsers which resources can be loaded. It prevents:
- Cross-site scripting (XSS) attacks
- Data injection attacks
- Clickjacking
- Mixed content issues
Basic CSP Header
Content-Security-Policy: default-src 'self'
This only allows resources from the same origin.
Common Directives
| Directive | Purpose | Example |
|-----------|---------|---------|
| default-src | Fallback for other directives | default-src 'self' |
| script-src | Allowed JavaScript sources | script-src 'self' 'unsafe-inline' |
| style-src | Allowed CSS sources | style-src 'self' 'unsafe-inline' |
| img-src | Allowed image sources | img-src 'self' https://images.example.com |
| connect-src | Allowed fetch/XHR targets | connect-src 'self' https://api.example.com |
| font-src | Allowed font sources | font-src 'self' https://fonts.example.com |
| frame-src | Allowed iframe sources | frame-src 'none' |
Practical Examples
Basic Security (Recommended Start)
Content-Security-Policy:
default-src 'self';
script-src 'self';
object-src 'none';
Allow External Scripts Safely
Content-Security-Policy:
default-src 'self';
script-src 'self' https://cdn.example.com;
style-src 'self' 'unsafe-inline';
Google Analytics + Fonts
Content-Security-Policy:
default-src 'self';
script-src 'self' https://www.google-analytics.com;
style-src 'self' https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com;
img-src 'self' https://www.google-analytics.com;
Strict Policy (Most Secure)
Content-Security-Policy:
default-src 'none';
script-src 'self';
style-src 'self';
img-src 'self';
connect-src 'self';
base-uri 'self';
form-action 'self';
Implementing CSP
In Next.js (next.config.js)
module.exports = {
async headers() {
return [
{
source: '/(.*)',
headers: [
{
key: 'Content-Security-Policy',
value: "default-src 'self'; script-src 'self' 'unsafe-inline';"
}
]
}
];
}
};
In Express.js
app.use((req, res, next) => {
res.setHeader(
'Content-Security-Policy',
"default-src 'self'; script-src 'self' 'unsafe-inline'"
);
next();
});
Using Meta Tag
<head>
<meta http-equiv="Content-Security-Policy"
content="default-src 'self';">
</head>
Monitoring CSP Violations
Report-Only Mode (Testing)
Content-Security-Policy-Report-Only:
default-src 'self';
report-uri /api/csp-report;
Backend Handler (Node.js)
app.post('/api/csp-report', express.json(), (req, res) => {
const violation = req.body['csp-report'];
console.log('CSP Violation:', violation);
// Log to monitoring service
logger.error('CSP violation', violation);
res.status(204).end();
});
Common Issues and Fixes
Issue: Inline Scripts Blocked
// Won't work with default-src 'self'
<button onclick="doSomething()">Click</button>
// Use instead
<button id="myButton">Click</button>
// In external JS
document.getElementById('myButton').addEventListener('click', doSomething);
Issue: Google Fonts Blocked
<!-- Add to CSP -->
font-src 'self' https://fonts.gstatic.com;
style-src 'self' https://fonts.googleapis.com;
Issue: Analytics Blocked
<!-- Add to CSP -->
script-src 'self' https://www.google-analytics.com;
img-src 'self' https://www.google-analytics.com;
Nonce-Based Inline Scripts
// Generate unique nonce
const nonce = crypto.randomBytes(16).toString('base64');
// Set header
res.setHeader('Content-Security-Policy',
`script-src 'self' 'nonce-${nonce}'`);
// Use in HTML
<script nonce="<%= nonce %>">
// This script will run
</script>
Testing Your CSP
- Use report-only mode first
- Check browser console for violations
- Use CSP Evaluator - https://csp-evaluator.withgoogle.com
- Start strict, then relax as needed
Conclusion
Start with a restrictive CSP in report-only mode, monitor violations, then gradually tighten. A good CSP significantly reduces your attack surface.