Cross-Site Scripting (XSS) and Cross-Site Request Forgery (CSRF)Lesson 3.2
Content Security Policy: how to block XSS at the browser level
CSP directives, script-src nonce, hash-based CSP, unsafe-inline risks, CSP reporting, report-uri, strict CSP, CSP level 3
Content Security Policy (CSP)
CSP is a browser-enforced whitelist of sources from which scripts, styles, images, and other resources may load. A well-configured CSP blocks XSS execution even when an injection flaw exists in your code.
Building a Strict CSP
// Strict CSP using nonces — most effective approach
app.use((req, res, next) => {
const nonce = crypto.randomBytes(16).toString('base64');
res.locals.nonce = nonce;
res.setHeader('Content-Security-Policy',
`default-src 'self'; ` +
`script-src 'nonce-${nonce}' 'strict-dynamic'; ` +
`style-src 'self'; ` +
`img-src 'self' data:; ` +
`object-src 'none'; ` +
`base-uri 'none'; ` +
`report-uri /csp-report`
);
next();
});
// In your HTML template:
// Why 'unsafe-inline' Defeats the Purpose
Adding 'unsafe-inline' to script-src allows any inline script to execute, which is exactly what XSS payloads use. A CSP with 'unsafe-inline' provides almost no XSS protection. Use nonces instead—a unique per-request token added to your own script tags.
CSP Reporting
// Catch violations without blocking (useful for initial deployment)
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report
// Log the violation report
app.post('/csp-report', express.json({ type: 'application/csp-report' }), (req, res) => {
console.error('CSP Violation:', req.body);
res.sendStatus(204);
});Deploy in report-only mode first, review violations for legitimate content, then switch to enforcement mode.
