En algunas circunstancias, los pimientos pueden ser útiles.
Como ejemplo típico, digamos que estás creando una aplicación web. Consiste en un código de aplicación web (que se ejecuta en algún marco de aplicación web, ASP.NET MVC, Pyramid on Python, no importa ) y una base de datos SQL para almacenamiento. La aplicación web y la base de datos SQL se ejecutan en diferentes servidores físicos .
El ataque más común contra la base de datos es un ataque de inyección SQL exitoso. Este tipo de ataque no necesariamente obtiene acceso a su código de aplicación web, porque la aplicación web se ejecuta en un servidor diferente & ID de usuario.
Debe almacenar las contraseñas de forma segura en la base de datos, y encontrar algo en la forma de:
$hashed_password = hash( $salt . $password )
donde $salt
se almacena en texto plano en la base de datos, junto con la representación $hashed_password
y elegidos al azar para cada contraseña nueva o cambiada .
El aspecto más importante de cada esquema de hash de contraseñas es que hash
es una función hash criptográficamente segura lenta , consulte enlace para obtener más información sobre los antecedentes.
La pregunta es, entonces, dado que es un esfuerzo casi nulo para agregar un valor constante al código de la aplicación, y que el código de la aplicación normalmente no se verá comprometido durante un ataque de inyección de SQL, ¿es lo siguiente sustancialmente mejor que lo anterior?
$hashed_password = hash( $pepper . $salt . $password )
donde $salt
se almacena en texto sin formato en la base de datos, y $pepper
es una constante almacenada en texto sin formato en el código de la aplicación (o configuración si el código se usa en múltiples servidores o la fuente es pública).
Es fácil agregar este $pepper
: solo estás creando una constante en tu código, ingresando un gran valor aleatorio criptográficamente seguro (por ejemplo, 32 bytes de / dev / urandom hex o base64 codificado) y usándolo constante en la función de hashing de contraseñas. Si tiene usuarios existentes, necesita una estrategia de migración, por ejemplo, vuelva a introducir la contraseña en el siguiente inicio de sesión y almacene un número de versión de la estrategia de hash de contraseña junto con el hash.
Respuesta:
El uso de $pepper
se agrega a la fuerza del hash de contraseña si el compromiso de la base de datos no implica el compromiso de la aplicación . Sin conocimiento de la pimienta las contraseñas permanecen completamente seguras. Debido a la sal específica de la contraseña, ni siquiera puede descubrir si dos contraseñas en la base de datos son iguales o no.
La razón es que hash($pepper . $salt . $password)
construye efectivamente una función pseudoaleatoria con $pepper
como clave y $salt.$password
como entrada (para candidatos sane hash
como PBKDF2 con SHA *, bcrypt o scrypt). Dos de las garantías de una función pseudoaleatoria son que no puede deducir la entrada de la salida bajo una clave secreta y tampoco la salida de la entrada sin el conocimiento de la clave. Esto se parece mucho a la propiedad unidireccional de las funciones hash, pero la diferencia radica en el hecho de que con valores de entropía bajos, como contraseñas, puede enumerar efectivamente todos los valores posibles y calcular las imágenes bajo la función hash pública y así encontrar el valor cuyo valor La imagen coincide con la imagen previa. Con una función pseudoaleatoria, no puede hacerlo sin la clave (es decir, sin la pimienta), ya que ni siquiera puede calcular la imagen de un solo valor sin la clave.
El importante papel del $salt
en esta configuración entra en juego si tiene acceso a la base de datos durante un tiempo prolongado y normalmente puede trabajar con la aplicación desde el exterior. Sin el $salt
, podría establecer la contraseña de una cuenta que controle con un valor conocido $passwordKnown
y comparar el hash con la contraseña de una contraseña desconocida $passwordSecret
. Como hash($pepper . $passwordKnown)==hash($pepper . $passwordSecret)
si y solo si $passwordKnown==$passwordSecret
puede comparar una contraseña desconocida con cualquier valor elegido (como tecnicidad supongo que la resistencia a la colisión de la función hash). Pero con la sal obtienes hash($pepper . $salt1 . $passwordKnown)==hash($pepper . $salt2 . $passwordSecret)
si y solo si $salt1 . $passwordKnown == $salt2 . $passwordSecret
y como $salt1
y $salt2
fueron elegidos al azar para $passwordKnown
y respectivamente $passwordSecret
las sales nunca serán las mismas (asumiendo valores aleatorios suficientemente grandes como 256 bits) y, por lo tanto, ya no se pueden comparar las contraseñas entre sí.