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.

Common Policies

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

  1. The server generates a random nonce for each request (e.g., abc123def456)
  2. The nonce is included in the CSP header:
    Content-Security-Policy: script-src 'nonce-abc123def456'
    
  3. The same nonce is added to allowed elements:
    <script nonce="abc123def456">
      // This script is allowed
    </script>
    
  4. 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-store or 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.

Try It — CSP Header Generator

Open full tool