Using Nonces in CSP Headers
Implement nonce-based Content Security Policy to allow specific inline scripts and styles without unsafe-inline. Learn nonce generation, server integration, and strict-dynamic.
Detailed Explanation
Nonce-Based CSP
A nonce (number used once) is a cryptographically random token generated on each HTTP response. By including this nonce in both the CSP header and on allowed <script> or <style> elements, you can permit specific inline code without resorting to 'unsafe-inline'.
How It Works
- The server generates a random nonce for each request (e.g.,
abc123def456) - The nonce is included in the CSP header:
Content-Security-Policy: script-src 'nonce-abc123def456' - The same nonce is added to allowed elements:
<script nonce="abc123def456"> // This script is allowed </script> - Scripts without the matching nonce are blocked
Nonce Requirements
- Cryptographically random — use
crypto.randomBytes(16).toString('base64')in Node.js or equivalent - At least 128 bits of entropy (16 bytes)
- Unique per response — never reuse a nonce across requests
- Base64-encoded — the value must be valid base64
Server-Side Implementation
Node.js / Express:
const crypto = require('crypto');
app.use((req, res, next) => {
const nonce = crypto.randomBytes(16).toString('base64');
res.locals.nonce = nonce;
res.setHeader('Content-Security-Policy',
`script-src 'nonce-${nonce}' 'strict-dynamic'; style-src 'nonce-${nonce}'`
);
next();
});
Combining Nonces with strict-dynamic
'strict-dynamic' allows scripts loaded by nonced scripts to execute without their own nonce:
Content-Security-Policy: script-src 'strict-dynamic' 'nonce-abc123'
This means your main bundle (which has the nonce) can dynamically load additional scripts via document.createElement('script'), and those will be trusted automatically. This is essential for applications using code splitting or lazy loading.
Common Pitfalls
- Nonce in HTML cache — if your HTML is cached by a CDN, the nonce becomes stale. Use
Cache-Control: no-storeor edge-side nonce injection - Nonce leakage — never expose the nonce value to JavaScript via global variables; XSS could read and reuse it
- Framework support — ensure your template engine passes the nonce to all
<script>and<style>tags
Use Case
Nonce-based CSP is the recommended approach for modern web applications that need inline scripts. Server-rendered apps (Next.js, Express, Django) can generate a nonce per request and inject it into both the header and the HTML. This is especially important for applications that use inline configuration scripts, analytics snippets, or server-rendered initial state.