para ninguno los kit herramienta hashes generar firma desarrollo desarrolladores depuración con coincide claves clave certificados certificado almacenados administración security encryption password-protection hmac

security - ninguno - Uso de HMAC-SHA1 para autenticación API: ¿cómo almacenar la contraseña del cliente de forma segura?



herramienta de administración de claves y certificados keytool del kit para desarrolladores de java (3)

En una API RESTful que utiliza la autenticación de S3-style , el cliente API firma la solicitud con su clave secreta utilizando HMAC-SHA1, por lo que la clave secreta nunca se transmite por cable. A continuación, el servidor autentica al cliente utilizando la clave secreta de ese cliente para repetir el proceso de firma y comparar el resultado con la firma transmitida por el cliente.

Todo esto es agradable y bueno, pero significa que el servidor requiere acceso al texto claro del secreto compartido del cliente. Eso va en contra de todos los consejos que existen en contra de almacenar las contraseñas de los usuarios en el claro dentro de su base de datos. Almacenar solo el hash salado de la contraseña no es una opción por lo que puedo decir, porque entonces no puedo verificar la firma del cliente.

Debo enfatizar que mi API es REST y por lo tanto debe ser sin estado: prefiero evitar un paso de inicio de sesión antes de otras llamadas a la API.

Una solución opcional es cifrar todas las contraseñas de los usuarios utilizando algún algoritmo de clave simétrica. Sin embargo, el servidor tendría que almacenar la clave de ese cifrado en algún lugar de fácil acceso , por ejemplo, dentro del código fuente. Esto es mejor que nada, pero no una solución óptima (como @Rook se menciona en su respuesta, viola CWE-257).

Otra dirección para una solución podría ser algo relacionado con las firmas asimétricas, pero no puedo averiguar cómo aplicar eso al HMAC, y no puedo encontrar ningún artículo sobre el tema.

¿Me estoy perdiendo algo obvio aquí? Muchos proveedores respetables han implementado este tipo de esquema de autenticación: no todos pueden estar violando principios de seguridad comunes, ¿o sí? Si no, ¿hay alguna mejor práctica que puedas compartir?


Esta es la desventaja de la autenticación de estilo desafío-respuesta de clave simétrica: no pone el secreto en el cable, pero tiene que almacenar el secreto en ambos extremos. (HMAC son sistemas de claves simétricas).

Sin embargo, tenga en cuenta que no es una contraseña , es un secreto compartido . Aquí hay una diferencia fundamental: generalmente, el usuario elige una contraseña, mientras que un secreto compartido se genera de forma aleatoria y se le proporciona al usuario (a menudo se denominan "claves de API" en este contexto).

Almacenar contraseñas en un formato reversible es malo, porque si su base de datos está en peligro, los atacantes han obtenido contraseñas que podrían (y probablemente se han usado) en otro lugar. Almacenar un secreto compartido, por otro lado, no es un problema: el secreto es específico de su servicio, por lo que todos los atacantes han obtenido la capacidad de iniciar sesión en su servicio.

Por otro lado, es posible tener un sistema asimétrico que no tenga que almacenar un secreto en el lado del servidor. La idea básica es que el servidor conozca la clave pública del cliente y el número de secuencia del mensaje actual. Al enviar una solicitud de API, el cliente incrementa el número de secuencia de mensaje y calcula una firma sobre el número de secuencia y los parámetros de solicitud de API, que el servidor puede verificar utilizando la clave pública. El servidor rechaza un mensaje si contiene un número de secuencia de mensaje anterior para evitar ataques de repetición.


Lo ideal es que, después de que el usuario inicie sesión, les dé un Nonce criptográfico que se utilice como la clave secreta K de HMAC durante toda la sesión. Este es un enfoque seguro, pero no RESTful, porque REST no tiene estado. Esta idea de un código de autenticación de mensaje emitido por inicio de sesión es técnicamente una forma de estado.

Cifrar contraseñas y almacenarlas en la base de datos es una violación de CWE-257 .


No estoy seguro de si me falta algo aquí, pero una opción es usar contraseña hash como clave simétrica.