La semana pasada leí muchos artículos sobre el hash de contraseñas y Blowfish parece ser (uno de) los mejores algoritmos de hash en este momento, ¡pero ese no es el tema de esta pregunta!
El límite de 72 caracteres
Blowfish solo considera los primeros 72 caracteres en la contraseña ingresada:
<?php
$password = "Wow. This is a super secret and super, super long password. Let's add some special ch4r4ct3rs a#d everything is fine :)";
$hash = password_hash($password, PASSWORD_BCRYPT);
var_dump($password);
$input = substr($password, 0, 72);
var_dump($input);
var_dump(password_verify($input, $hash));
?>
La salida es:
string(119) "Wow. This is a super secret and super, super long password. Let's add some special ch4r4ct3rs a#d everything is fine :)"
string(72) "Wow. This is a super secret and super, super long password. Let's add so"
bool(true)
Como puede ver, solo importan los primeros 72 caracteres. Twitter está utilizando blowfish, también conocido como bcrypt, para almacenar sus contraseñas ( https://shouldichangemypassword.com/twitter-hacked.php ) y adivina qué: cambia tu contraseña de Twitter a una contraseña larga con más de 72 caracteres y puedes iniciar sesión en tu cuenta mediante ingresando solo los primeros 72 caracteres.
Pez globo y pimienta
Hay muchas opiniones diferentes sobre las contraseñas de "pimienta". Algunas personas dicen que es innecesario, porque hay que asumir que el hilo de pimienta secreto también es conocido / publicado, por lo que no mejora el hash. Tengo un servidor de base de datos separado, por lo que es muy posible que solo se filtre la base de datos y no la pimienta constante.
En este caso (pimienta no filtrada) haces más difícil un ataque basado en un diccionario (corrígeme si esto no es correcto). Si su hilo de pimienta también tiene una fuga: no está tan mal, todavía tiene la sal y está tan bien protegida como un picadillo sin pimienta.
Así que creo que modificar la contraseña no es una mala elección.
Sugerencia
Mi sugerencia para obtener un hash Blowfish para una contraseña con más de 72 caracteres (y pimienta) es:
<?php
$pepper = "foIwUVmkKGrGucNJMOkxkvcQ79iPNzP5OKlbIdGPCMTjJcDYnR";
// Generate Hash
$password = "Wow. This is a super secret and super, super long password. Let's add some special ch4r4ct3rs a#d everything is fine :)";
$password_peppered = hash_hmac('sha256', $password, $pepper);
$hash = password_hash($password_peppered, PASSWORD_BCRYPT);
// Check
$input = substr($password, 0, 72);
$input_peppered = hash_hmac('sha256', $input, $pepper);
var_dump(password_verify($input_peppered, $hash));
?>
Esto se basa en esta pregunta : password_verify
regreso false
.
La pregunta
¿Cuál es la forma más segura? ¿Obtener primero un hash SHA-256 (que devuelve 64 caracteres) o considerar solo los primeros 72 caracteres de la contraseña?
Pros
- El usuario no puede iniciar sesión ingresando solo los primeros 72 caracteres
- Puede agregar la pimienta sin exceder el límite de caracteres
- La salida de hash_hmac probablemente tendría más entropía que la contraseña misma
- La contraseña está codificada por dos funciones diferentes
Contras
- Solo se utilizan 64 caracteres para construir el hash de pez globo
Edición 1: esta pregunta aborda solo la integración PHP de blowfish / bcrypt. ¡Gracias por los comentarios!
Respuestas:
El problema aquí es básicamente un problema de entropía. Así que comencemos a buscar allí:
Entropía por carácter
El número de bits de entropía por byte es:
Entonces, cómo actuamos depende del tipo de personajes que esperamos.
El primer problema
El primer problema con su código es que su paso de hash "pimienta" está generando caracteres hexadecimales (ya que el cuarto parámetro
hash_hmac()
no está configurado).Por lo tanto, al aplicar hash a su pimienta, está efectivamente reduciendo la entropía máxima disponible para la contraseña en un factor de 2 (de 576 a 288 bits posibles ).
El segundo problema
Sin embargo,
sha256
solo proporciona256
bits de entropía en primer lugar. De modo que está reduciendo efectivamente 576 bits a 256 bits. Su paso hash * inmediatamente *, por definición, pierde al menos el 50% de la posible entropía en la contraseña.Podría resolver esto parcialmente cambiando a
SHA512
, donde solo reduciría la entropía disponible en aproximadamente un 12%. Pero esa sigue siendo una diferencia significativa. Ese 12% reduce el número de permutaciones en un factor de1.8e19
. Ese es un gran número ... Y ese es el factor que lo reduce por ...El problema subyacente
El problema subyacente es que hay tres tipos de contraseñas de más de 72 caracteres. El impacto que este sistema de estilo tiene en ellos será muy diferente:
Nota: de aquí en adelante, supongo que estamos comparando con un sistema de pimienta que se usa
SHA512
con salida sin procesar (no hexadecimal).Contraseñas aleatorias de alta entropía
Estos son sus usuarios que utilizan generadores de contraseñas que generan claves grandes para contraseñas. Son aleatorios (generados, no elegidos por humanos) y tienen una alta entropía por carácter. Estos tipos utilizan bytes altos (caracteres> 127) y algunos caracteres de control.
Para este grupo, su función hash reducirá significativamente su entropía disponible en
bcrypt
.Déjame decirlo de nuevo. Para los usuarios que utilizan contraseñas largas de alta entropía, su solución reduce significativamente la seguridad de su contraseña en una cantidad mensurable. (62 bits de entropía perdidos para una contraseña de 72 caracteres y más para contraseñas más largas)
Contraseñas aleatorias de entropía media
Este grupo utiliza contraseñas que contienen símbolos comunes, pero no bytes altos ni caracteres de control. Estas son sus contraseñas que se pueden escribir.
Para este grupo, va a desbloquear un poco más entropía (no crearla, pero permitir que más entropía quepa en la contraseña de bcrypt). Cuando digo un poco, me refiero a un poco. El punto de equilibrio se produce cuando maximiza los 512 bits que tiene SHA512. Por lo tanto, el pico es de 78 caracteres.
Déjame decirlo de nuevo. Para esta clase de contraseñas, solo puede almacenar 6 caracteres adicionales antes de quedarse sin entropía.
Contraseñas no aleatorias de baja entropía
Este es el grupo que utiliza caracteres alfanuméricos que probablemente no se generen al azar. Algo como una cita bíblica o algo así. Estas frases tienen aproximadamente 2,3 bits de entropía por carácter.
Para este grupo, puede desbloquear significativamente más entropía (no crearla, pero permitir que más se ajuste a la entrada de contraseña de bcrypt) mediante hash. El punto de equilibrio es de alrededor de 223 caracteres antes de que te quedes sin entropía.
Digámoslo de nuevo. Para esta clase de contraseñas, el pre-hash definitivamente aumenta la seguridad de manera significativa.
De vuelta al mundo real
Este tipo de cálculos de entropía realmente no importan mucho en el mundo real. Lo que importa es adivinar la entropía. Eso es lo que afecta directamente lo que pueden hacer los atacantes. Eso es lo que quieres maximizar.
Si bien se ha realizado poca investigación para adivinar la entropía, hay algunos puntos que me gustaría señalar.
Las posibilidades de adivinar al azar 72 caracteres correctos seguidos son extremadamente bajas. Es más probable que ganes la lotería Powerball 21 veces, que tener esta colisión ... Así de grande es el número del que estamos hablando.
Pero es posible que no lo encontremos estadísticamente. En el caso de las frases, la probabilidad de que los primeros 72 caracteres sean iguales es mucho mayor que para una contraseña aleatoria. Pero sigue siendo trivialmente bajo (es más probable que ganes la lotería Powerball 5 veces, según 2.3 bits por carácter).
Prácticamente
Prácticamente, realmente no importa. Las posibilidades de que alguien adivine correctamente los primeros 72 caracteres, donde los últimos marcan una diferencia significativa, son tan bajas que no vale la pena preocuparse. ¿Por qué?
Bueno, digamos que estás tomando una frase. Si la persona puede acertar con los primeros 72 caracteres, es muy afortunado (no es probable) o es una frase común. Si es una frase común, la única variable es cuánto tiempo debe hacerse.
Pongamos un ejemplo. Tomemos una cita de la Biblia (solo porque es una fuente común de texto extenso, no por ninguna otra razón):
Eso es 180 caracteres. El carácter 73 es el
g
del segundoneighbor's
. Si adivinó tanto, es probable que no se detenga ennei
, sino que continúe con el resto del versículo (ya que así es como es probable que se use la contraseña). Por lo tanto, su "hash" no agregó mucho.Por cierto: Absolutamente NO estoy abogando por el uso de una cita bíblica. De hecho, todo lo contrario.
Conclusión
Realmente no vas a ayudar mucho a las personas que usan contraseñas largas usando hash primero. Algunos grupos definitivamente pueden ayudar. Algunos definitivamente puedes lastimarlos.
Pero al final, nada de eso es demasiado significativo. Los números con los que estamos lidiando son MUY demasiado altos. La diferencia de entropía no será mucha.
Es mejor dejar bcrypt como está. Es más probable que arruines el hash (literalmente, ya lo has hecho y no eres el primero ni el último en cometer ese error) que el ataque que estás tratando de prevenir.
Concéntrese en asegurar el resto del sitio. Y agregue un medidor de entropía de contraseña al cuadro de contraseña al registrarse para indicar la fuerza de la contraseña (e indicar si una contraseña es demasiado larga y el usuario puede desear cambiarla) ...
Ese es mi $ 0.02 al menos (o posiblemente mucho más de $ 0.02) ...
En cuanto al uso de un pimiento "secreto":
Literalmente, no hay ninguna investigación sobre la introducción de una función hash en bcrypt. Por lo tanto, no está claro en el mejor de los casos si introducir un hash "salpicado" en bcrypt alguna vez causará vulnerabilidades desconocidas (sabemos que hacerlo
hash1(hash2($value))
puede exponer vulnerabilidades significativas en torno a la resistencia a colisiones y los ataques de preimagen).Teniendo en cuenta que ya está considerando almacenar una clave secreta (el "pimiento"), ¿por qué no usarla de una manera bien estudiada y comprendida? ¿Por qué no cifrar el hash antes de almacenarlo?
Básicamente, después de aplicar el hash a la contraseña, introduzca toda la salida del hash en un algoritmo de cifrado sólido. Luego almacene el resultado encriptado.
Ahora, un ataque de inyección de SQL no filtrará nada útil, porque no tienen la clave de cifrado. Y si se filtra la clave, los atacantes no estarán mejor que si usas un hash simple (lo cual es demostrable, algo con el pimiento "pre-hash" no proporciona).
Nota: si elige hacer esto, use una biblioteca. Para PHP, recomiendo encarecidamente el
Zend\Crypt
paquete Zend Framework 2 . De hecho, es el único que recomendaría en este momento. Ha sido revisado enérgicamente y toma todas las decisiones por usted (lo cual es algo muy bueno) ...Algo como:
Y es beneficioso porque está utilizando todos los algoritmos de formas que se comprenden y se estudian bien (al menos relativamente). Recuerda:
fuente
Sin duda, modificar las contraseñas es algo bueno, pero veamos por qué.
Primero debemos responder a la pregunta de cuándo ayuda exactamente un pimiento. El pimiento solo protege las contraseñas, siempre que se mantenga en secreto, por lo que si un atacante tiene acceso al servidor, no sirve de nada. Sin embargo, un ataque mucho más fácil es la inyección SQL, que permite el acceso de lectura a la base de datos (a nuestros valores hash), preparé una demostración de inyección SQL para mostrar lo fácil que puede ser (haga clic en la flecha siguiente para obtener un entrada).
Entonces, ¿qué ayuda realmente la pimienta? Mientras el pimiento permanezca en secreto, protege las contraseñas débiles de un ataque de diccionario. La contraseña
1234
se convertiría entonces en algo así como1234-p*deDIUZeRweretWy+.O
. Esta contraseña no solo es mucho más larga, también contiene caracteres especiales y nunca formará parte de ningún diccionario.Ahora podemos estimar qué contraseñas usarán nuestros usuarios, probablemente más usuarios ingresarán contraseñas débiles, ya que hay usuarios con contraseñas entre 64-72 caracteres (en realidad esto será muy raro).
Otro punto es el rango de la fuerza bruta. La función hash sha256 devolverá una salida de 256 bits o combinaciones de 1.2E77, eso es demasiado para la fuerza bruta, incluso para las GPU (si calculé correctamente, esto necesitaría aproximadamente 2E61 años en una GPU en 2013). Por lo que no obtenemos una verdadera desventaja aplicando el pimiento. Debido a que los valores hash no son sistemáticos, no puede acelerar la fuerza bruta con patrones comunes.
PD: Hasta donde yo sé, el límite de 72 caracteres es específico del algoritmo de BCrypt. La mejor respuesta que encontré es esta .
PPS Creo que su ejemplo es defectuoso, no puede generar el hash con la longitud completa de la contraseña y verificarlo con una truncada. Probablemente quisiste aplicar el pimiento de la misma manera para generar el picadillo y para verificarlo.
fuente
true
. De eso se trata esta pregunta. ÉchaleBcrypt utiliza un algoritmo basado en el costoso algoritmo de configuración de claves Blowfish.
El límite de contraseña recomendado de 56 bytes (incluido el byte de terminación nulo) para bcrypt se relaciona con el límite de 448 bits de la clave Blowfish. Los bytes que superen ese límite no se mezclan completamente en el hash resultante. El límite absoluto de 72 bytes en las contraseñas bcrypt es, por lo tanto, menos relevante, si se considera el efecto real de esos bytes en el hash resultante.
Si cree que sus usuarios normalmente elegirían contraseñas de más de 55 bytes de longitud, recuerde que siempre puede aumentar las rondas de estiramiento de contraseñas, para aumentar la seguridad en el caso de una violación de la tabla de contraseñas (aunque esto tiene que ser mucho en comparación con agregar más caracteres). Si los derechos de acceso de los usuarios son tan críticos que los usuarios normalmente requerirían una contraseña enormemente larga, entonces la caducidad de la contraseña también debería ser corta, como 2 semanas. Esto significa que es mucho menos probable que una contraseña siga siendo válida mientras un pirata informático invierte sus recursos en vencer el factor de trabajo involucrado en probar cada contraseña de prueba para ver si produce un hash coincidente.
Por supuesto, en el caso de que la tabla de contraseñas no sea violada, solo deberíamos permitir a los piratas informáticos, como máximo, diez intentos de adivinar la contraseña de 55 bytes de un usuario, antes de bloquear la cuenta del usuario;)
Si decide realizar un hash previo de una contraseña de más de 55 bytes, entonces debe usar SHA-384, ya que tiene la salida más grande sin sobrepasar el límite.
fuente