Qué es un nonce y por qué importa
Un nonce (number used once) es un valor único que se usa una sola vez para prevenir ataques de replay. Si un atacante captura una request válida y la reenvía, el nonce ya usado es rechazado.
Los nonces son críticos en: OAuth flows (previene CSRF), JWT tokens (claim 'jti' para one-time use), webhooks (valida que el payload no fue manipulado), CSP headers (permite scripts inline seguros), y transacciones financieras (evita double-spend).
Un nonce efectivo debe ser: impredecible (criptográficamente aleatorio), único (no repetible), de tiempo limitado (expira después de X segundos o tras primer uso). Usar timestamps solos NO es suficiente: son predecibles. Combina timestamp + randomBytes + HMAC para nonces robustos.
Implementando nonces en Node.js y navegadores
En Node.js, usa crypto.randomBytes(16) del módulo nativo. Para URL-safe strings, convierte a base64url o hex. Ejemplo: crypto.randomBytes(16).toString('base64url') genera strings como 'a3f8B2kL9xR4'.
En navegadores modernos, usa crypto.getRandomValues(new Uint8Array(16)) y convierte a hex con Array.from(bytes).map(b => b.toString(16).padStart(2,'0')).join(''). Evita Math.random(): no es criptográficamente seguro.
Para nonces con timestamp, concatena millis + random: Date.now() + '_' + crypto.randomBytes(8).toString('hex'). Esto permite ordenamiento temporal mientras mantiene unicidad. Almacena nonces usados en Redis con TTL de 5-10 minutos para prevenir reuso dentro de la ventana de replay.
Nonces en OAuth y PKCE
En OAuth 2.0, el parámetro 'state' funciona como nonce para prevenir CSRF. Genera un valor aleatorio, guárdalo en sesión o cookie httpOnly, y valida que el callback lo devuelve idéntico.
PKCE (Proof Key for Code Exchange) usa dos nonces: code_verifier (43-128 chars URL-safe random) y code_challenge (SHA256 del verifier en base64url). El authorization endpoint recibe el challenge, el token endpoint valida el verifier. Esto previene authorization code interception en apps públicas.
En OpenID Connect, el claim 'nonce' se incluye en el ID token. El cliente genera un nonce aleatorio, lo pasa en el request, y verifica que el token devuelto lo contiene. Esto ata el token al request específico, previniendo token substitution attacks.
Content Security Policy y nonces para scripts
CSP nonces permiten ejecutar scripts inline seguros sin 'unsafe-inline'. Genera un nonce por request: const nonce = crypto.randomBytes(16).toString('base64'). Añadí el header: Content-Security-Policy: script-src 'nonce-${nonce}'.
En el HTML, cada script inline debe incluir el atributo: <script nonce='${nonce}'>...</script>. El browser solo ejecuta scripts con nonce correcto. Importante: el nonce debe ser diferente por cada response (no reutilices entre requests).
Para frameworks SSR (Next.js, Nuxt), configura el nonce en el middleware y pásalo al render context. En Express: res.locals.nonce = generateNonce(), luego en templates: <script nonce='<%= nonce %>'>. Combina con strict-dynamic para permitir scripts cargados por scripts con nonce válido.