← Recipes

阅读中文版本

Harden Content Security Policy with Nonces

Drop unsafe-inline, generate a per-response nonce for legitimate scripts, and report violations so a CSP actually blocks injected scripts.

~40 minsecuritycspweb

Task

Make a Content Security Policy effective by replacing unsafe-inline with nonces.

When to use this

A CSP is deployed but includes unsafe-inline, so any injected script still runs and the policy provides no XSS protection.

Prerequisites

  • Control over HTML rendering to inject nonces
  • A report endpoint for violations

Steps

1. Generate a random nonce per response and add it to the script tags you control.

Expected output: Only your scripts carry the valid nonce.

2. Set a policy without unsafe-inline that requires the nonce for scripts.

Expected output: Injected inline scripts are blocked.

3. Add report-uri or report-to so violations are collected.

Expected output: You can see what would break before enforcing.

4. Roll out in report-only mode first, fix violations, then enforce.

curl -sI https://app.example.com | grep -i content-security-policy

Expected output: Enforcement does not break the site.

Troubleshooting

Problem

Site breaks on enforcement

Solution

Run report-only first and fix inline handlers and third-party scripts before switching to enforce.

Problem

Legacy inline handlers

Solution

Replace onclick attributes with listeners; nonces do not apply to inline event handlers.

Limitations

  • Nonces require per-response HTML generation and do not work with static HTML unless combined with hashes.
  • A strict CSP can conflict with third-party widgets that inject their own scripts.

Context

Make a Content Security Policy effective by replacing unsafe-inline with nonces. A CSP is deployed but includes unsafe-inline, so any injected script still runs and the policy provides no XSS protection.

Steps

  1. Generate a random nonce per response and add it to the script tags you control. Expected: Only your scripts carry the valid nonce.
  2. Set a policy without unsafe-inline that requires the nonce for scripts. Expected: Injected inline scripts are blocked.
  3. Add report-uri or report-to so violations are collected. Expected: You can see what would break before enforcing.
  4. Roll out in report-only mode first, fix violations, then enforce. Expected: Enforcement does not break the site.
const nonce = crypto.randomBytes(16).toString('base64');
res.setHeader('Content-Security-Policy',
  `default-src 'self'; script-src 'self' 'nonce-${nonce}'; object-src 'none'; base-uri 'none'`);

Verify

  • Only your scripts carry the valid nonce.
  • Injected inline scripts are blocked.
  • You can see what would break before enforcing.
  • Enforcement does not break the site.

Limits

  • Nonces require per-response HTML generation and do not work with static HTML unless combined with hashes.
  • A strict CSP can conflict with third-party widgets that inject their own scripts.