BookinglyTech News
Ciberseguridad

Verificar JWT sin caídas cuando el emisor rota su clave de firma

Refrescar el JWKS al ver un kid desconocido, con límite de frecuencia y una sola petición en vuelo, evita que la rotación de la clave de firma tumbe la autenticación.

3 min de lecturaDev.to0 vistas

Un servicio que acepta login con Google o GitHub y verifica los JWT en casa tiene un problema que va más allá de parsear el token: sobrevivir a la rotación de la clave de firma del emisor sin que los logins normales se conviertan en una caída. La receta es corta. Cuando la verificación se topa con un kid desconocido, el identificador de clave que viaja en la cabecera, hay que refrescar el JWKS del emisor una sola vez, bajo un límite de frecuencia, y reintentar. No vale esperar a que venza el temporizador de la caché.

El kid desconocido aparece porque el verificador lee la cabecera antes de comprobar la firma y busca una clave pública que coincida con ese identificador. Si el emisor publicó una clave nueva desde la última descarga, el token es legítimo y lo que está viejo es la caché local. El mensaje de error describe un fallo al seleccionar clave; no demuestra por sí solo que el token sea falso.

Tres casos que no se pueden mezclar en el log

Un kid conocido con firma inválida es un fallo de verificación. Un kid desconocido que aparece después de un refresco controlado es una rotación recuperada. Y un kid que sigue sin estar tras refrescar apunta a un token inválido o a una configuración de emisor equivocada. Meter los tres en el mismo contador de 401 destroza el rastro que hace falta para cuadrar los eventos de autenticación más adelante.

Un refresco, no uno por petición

El refresco tiene que ser único en vuelo y acotado. Varias peticiones pueden descubrir el mismo kid nuevo a la vez; el proceso debe hacer un solo intento y dejar una transición legible en la auditoría. Un mutex, un canal que sirva de señal de espera y una marca de tiempo con el intervalo mínimo resuelven la parte difícil. Nunca hay que iterar hasta que la clave aparezca: un token falso puede llevar un kid arbitrario, y una implementación sin límites convierte entrada controlada por el atacante en peticiones salientes repetidas contra el emisor. Si el refresco falla, los tokens cuyas claves ya están en caché se siguen verificando; los que necesitan la clave no disponible, no.

El formato del conjunto de claves, el JWKS, está definido en el RFC 7517, y el token en sí en el RFC 7519. Ese material es lo que se cachea y se indexa por kid; la verificación de firma y de claims debería seguir en manos de una librería JOSE mantenida, con issuer, audience y algoritmo esperados comprobados aparte.

El temporizador sigue teniendo sentido como mantenimiento de fondo, pero no puede ser el mecanismo de corrección. Con un intervalo de quince minutos, una rotación justo después de la descarga deja casi quince minutos en los que los tokens nuevos fallan. El valor exacto es una decisión local, no un hecho de seguridad: la ventana de fallo existe para cualquier intervalo positivo.

Lo que importa es pequeño y barato de implementar. Distinguir en métricas y logs un fallo de firma de un fallo de caché, y hacer que el refresco sea una operación única con timeouts de red normales. La rotación de claves es rutina en cualquier proveedor de identidad. Que tumbe el login es una decisión de implementación.