=== When to Use a CSP Nonce (and When Not To) ===
A **Content Security Policy (Nonce)** is a security mechanism used to allow specific, trusted inline ##<script>## or ##<style>## elements to execute on a webpage, even when a strict CSP is in place that otherwise blocks all inline code (e.g., by omitting ##'unsafe-inline'##).
==== 1. When You Need a CSP Nonce ====
You need a CSP nonce in the following scenarios:
* **Dynamic Inline Scripts/Styles**: When your server-side application generates unique inline JavaScript or CSS for each page load (e.g., injecting user-specific data, dynamic configuration, or one-time event handlers). Since the content changes with every request, a static hash cannot be precomputed.
* **Server-Side Rendering (SSR)**: Modern web frameworks (like Next.js, Django, or CodeIgniter) that render HTML on the server often include small, dynamic inline scripts. A nonce, generated per request, is the most practical way to allow these while maintaining security.
* **Using ##strict-dynamic##**: The ##strict-dynamic## keyword in a CSP policy trusts scripts that have a valid nonce or hash and allows *those scripts* to load additional, dynamically created scripts. Nonces work seamlessly with ##strict-dynamic## for building complex, modern web applications.
* **You Cannot Eliminate Inline Code**: If, for legitimate technical or legacy reasons, you cannot refactor your application to move all code into external ##.js## files, a nonce is a more secure alternative to the dangerous ##'unsafe-inline'## directive.
**Example (Next.js)**:
%%(hl javascript)
// A nonce is generated for every request
export function proxy(request) {
const nonce = crypto.randomUUID(); // Generate unique nonce
const cspHeader = `script-src 'nonce-${nonce}' 'strict-dynamic'`;
// ... set header and inject nonce into script tags
}
%%
==== 2. When You Do NOT Need a CSP Nonce ====
You should avoid using a nonce and opt for other methods when possible:
* **Static Inline Scripts/Styles**: If your inline code is identical on every page load (e.g., a small utility function or a static CSS class), use a **CSP Hash** instead. You calculate the hash (e.g., ##sha256-...##) of the script's content once and include it in your CSP header. This is more secure and allows for static page caching.
* **All Code is External**: The best practice is to have *no* inline scripts or styles. Put all your JavaScript in external ##.js## files and all your CSS in external ##.css## files. Your CSP can then simply use ##'self'## or specific domains for ##script-src## and ##style-src##, making nonces unnecessary.
* **Static Site Generation (SSG)**: For pages generated at build time (not per request), you cannot generate a unique nonce for each visitor. In this case, use CSP hashes for any required inline code.
* **Simplicity and Caching**: Nonces require dynamic header generation for every page, which prevents the HTML from being cached. If you don't need dynamic inline code, avoiding nonces simplifies your setup and improves performance.
==== Best Practices Summary ====
#|
*| Approach | Use Case | Pros | Cons |*
|| **Nonce** | Dynamic, server-rendered inline code | Easy to implement with SSR, works with ##strict-dynamic## | Must be unique per request, prevents HTML caching, requires server-side logic ||
|| **Hash** | Static inline code | Highly secure, allows static caching, header can be static | Hash must be recalculated if code changes, not suitable for dynamic content ||
|| **No Inline (Best)** | All code in external files | Maximum security, simple CSP, optimal caching | Requires refactoring legacy code ||
|#
**In short**: Use a nonce when you have **dynamic, server-rendered inline code** and cannot avoid it. Do not use a nonce (and prefer hashes or external files) for static content or when you can refactor to eliminate inline code entirely. Always prioritize moving code to external files.