tipos password_hash password encriptar encriptada encriptacion ejemplo desencriptar decrypt contraseñas contraseña con php security passwords cryptography password-hash

encriptar - password_hash php ejemplo



¿Es esta una buena función de contraseña hash en PHP? ¿Si no, porque no? (4)

El código que ha proporcionado es un puerto de PHPASS , específicamente el algoritmo "portátil". Tenga en cuenta la calificación de portable . Esto solo se aplicará a la biblioteca phpass si pasa true como el segundo parámetro constructor. De aquí en adelante en esta respuesta, phpass refiere SOLAMENTE al algoritmo portable, y no a la biblioteca misma. La biblioteca hará brypt por defecto si no especifica explícitamente portable ...

El equipo de PHPBB no desarrolló esto por sí mismo (algo muy bueno), sino que lo transfirió directamente desde phpass (discutible).

Hay algunas preguntas que deberíamos hacer aquí:

¿Es mala?

La respuesta corta es no, no está mal. Ofrece bastante buena seguridad. Si tiene un código sobre esto ahora mismo, no estaría apurado por abandonarlo. Es adecuado para la mayoría de los usos. Pero dicho esto, hay alternativas mucho mejores si estuviera comenzando un nuevo proyecto que yo no lo elegiría.

¿Cuáles son algunas debilidades?

  • Relativo a pbkdf2 : el algoritmo phpass usa hash() donde pbkdf2() usa hash_hmac() . Ahora, un HMAC ejecuta 2 hashes por cada llamada internamente, pero la implementación de PHP solo lleva aproximadamente 1.6 veces la ejecución de una sola llamada a hash() (¿no es C maravilloso?). Así que obtenemos 2 hashes de hash_hmac en el 62% del tiempo que tomaría hash() para ejecutar 2 hashes.

    Qué significa eso? Bueno, para un tiempo de ejecución dado , pbkdf2 ejecutará aproximadamente un 37.5% más hashes que el algoritmo phpass . Más hashes en un tiempo dado == bueno, porque da como resultado que se realice más cómputo.

    Entonces pbkdf2 es aproximadamente 37.5% más fuerte que phpass cuando se usa el mismo primitivo ( md5 en este caso). Pero pbkdf2 también puede tomar primitivas más fuertes. Entonces podemos usar pbkdf2 con sha512 para obtener una ventaja muy significativa sobre el algoritmo phpass (principalmente porque sha512 es un algoritmo más difícil con más computación que md5 ).

    Esto significa que no solo pbkdf2 puede generar más cálculos en la misma cantidad de tiempo, es capaz de generar cálculos más difíciles .

    Dicho esto, la diferencia no es demasiado significativa. Es mucho más medible, y pbkdf2 es definitivamente "más fuerte" que phpass .

  • Relativo a bcrypt : Esto es mucho más difícil de hacer. Pero veamos la superficie de eso. phpass usa md5 , y un bucle en PHP. pbkdf2 usa cualquier primitiva (en C) y un bucle en PHP. bcrypt usa un algoritmo personalizado todo en C (lo que significa que es un algoritmo diferente de cualquier hash disponible). Así que, claro del bate, bcrypt tiene una ventaja significativa que solo hace el hecho de que el algoritmo está todo en C. Esto permite más "computación" por unidad de tiempo. De este modo, se convierte en un algoritmo lento más eficiente (más cálculos en el tiempo de ejecución dado).

    Pero tan importante como la cantidad de cálculos que hace es la calidad de los cálculos. Esto podría ser un trabajo de investigación completo, pero en resumen, se reduce al hecho de que los cálculos que bcrypt usa internamente son mucho más difíciles de realizar que una función hash normal.

    Un ejemplo de la naturaleza más fuerte de bcrypt es el hecho de que bcrypt usa un estado interno mucho más grande que una función hash normal. SHA512 usa un estado interno de 512 bits para calcular contra un bloque de 1024 bits. bcrypt utiliza en su lugar aproximadamente 32 kb de estado interno para computar contra un único bloque de 576 bits. El hecho de que el estado interno de bcrypt sea ​​mucho más grande que SHA512 (y md5 y phpass ) explica en parte la naturaleza más fuerte de bcrypt .

Debería evitarse

Para nuevos proyectos, absolutamente . No es que sea malo. No lo es Es que hay algoritmos demostrablemente más fuertes (por órdenes de magnitud). Entonces, ¿por qué no usarlos?

Para obtener una prueba más de cómo bcrypt es más fuerte, consulte las diapositivas de Password13 (PDF) que lanzó un clúster de 25 GPU para descifrar hash de contraseñas. Aquí están los resultados relevantes:

  • md5($password)
    • 180 BILLONES de conjeturas por segundo
    • 9.4 horas - Todas las posibles contraseñas de 8 caracteres
  • sha1($password)
    • 61 MIL MILLONES DE SUPUESTOS POR SEGUNDO
    • 27 horas - Todas las contraseñas de 8 caracteres posibles
  • md5crypt (que es muy similar a phpass con un costo de 10):
    • 77 millones de conjeturas por segundo
    • 2.5 años - Todas las contraseñas de 8 caracteres posibles
  • bcrypt con un costo de 5
    • 71 mil conjeturas por segundo
    • 2700 años - Todas las contraseñas de 8 caracteres posibles

Nota: todas las posibles contraseñas de 8 caracteres están usando un conjunto de 94 caracteres:

a-zA-Z0-9~`!@#$%^&*()_+-={}|[]/:";''<>,.?/

La línea de fondo

Entonces, si está escribiendo código nuevo, sin duda use bcrypt . Si tiene phpass o pbkdf2 en producción ahora, es posible que desee actualizar, pero no es claro "usted es significativamente vulnerable".

Me pregunto si esta función (que en parte se toma de una versión de ~ 2 años de phpBB) es suficiente.

Si no, ¿por qué?
¿Y cómo lo cambiaría (haciendo que la transición sea perfecta para los usuarios existentes)?

El resultado de hash_pwd () es lo que se guardará en un DB.

function hash_pwd($password) { $itoa64 = ''./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz''; $random_state = $this->unique_id(); $random = ''''; $count = 6; if (($fh = @fopen(''/dev/urandom'', ''rb''))) { $random = fread($fh, $count); fclose($fh); } if (strlen($random) < $count) { $random = ''''; for ($i = 0; $i < $count; $i += 16) { $random_state = md5($this->unique_id() . $random_state); $random .= pack(''H*'', md5($random_state)); } $random = substr($random, 0, $count); } $hash = $this->_hash_crypt_private($password, $this->_hash_gensalt_private($random, $itoa64), $itoa64); if (strlen($hash) == 34) { return $hash; } return false; } function unique_id() { $val = microtime(); $val = md5($val); return substr($val, 4, 16); } function _hash_crypt_private($password, $setting, &$itoa64) { $output = ''*''; // Check for correct hash if (substr($setting, 0, 3) != ''$H$'') { return $output; } $count_log2 = strpos($itoa64, $setting[3]); if ($count_log2 < 7 || $count_log2 > 30) { return $output; } $count = 1 << $count_log2; $salt = substr($setting, 4, 8); if (strlen($salt) != 8) { return $output; } /** * We''re kind of forced to use MD5 here since it''s the only * cryptographic primitive available in all versions of PHP * currently in use. To implement our own low-level crypto * in PHP would result in much worse performance and * consequently in lower iteration counts and hashes that are * quicker to crack (by non-PHP code). */ if (PHP_VERSION >= 5) { $hash = md5($salt . $password, true); do { $hash = md5($hash . $password, true); } while (--$count); } else { $hash = pack(''H*'', md5($salt . $password)); do { $hash = pack(''H*'', md5($hash . $password)); } while (--$count); } $output = substr($setting, 0, 12); $output .= $this->_hash_encode64($hash, 16, $itoa64); return $output; } function _hash_gensalt_private($input, &$itoa64, $iteration_count_log2 = 6) { if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31) { $iteration_count_log2 = 8; } $output = ''$H$''; $output .= $itoa64[min($iteration_count_log2 + ((PHP_VERSION >= 5) ? 5 : 3), 30)]; $output .= $this->_hash_encode64($input, 6, $itoa64); return $output; } function _hash_encode64($input, $count, &$itoa64) { $output = ''''; $i = 0; do { $value = ord($input[$i++]); $output .= $itoa64[$value & 0x3f]; if ($i < $count) { $value |= ord($input[$i]) << 8; } $output .= $itoa64[($value >> 6) & 0x3f]; if ($i++ >= $count) { break; } if ($i < $count) { $value |= ord($input[$i]) << 16; } $output .= $itoa64[($value >> 12) & 0x3f]; if ($i++ >= $count) { break; } $output .= $itoa64[($value >> 18) & 0x3f]; } while ($i < $count); return $output; }


(Perdón por mi inglés al principio)

Hay pocas preguntas, que todos los comentaristas deben hacer antes de responder:

¿Dónde se usará ese código?

¿Qué tipo de datos protegerá?

¿Se usará para el sistema de nivel crítico?

Ok, tenemos algunos casos de uso. Estoy usando un generador de contraseñas simplificado para IS, sí, realmente no está preparado para la 3ra. Guerra Mundial, pero la posibilidad de que el usuario le diga la contraseña a alguien o de que algún malware de su computadora sea filtrado es mucho más grande.

  • md5 es débil, use el generador de huellas digitales más nuevo (sha128, sha256, sha512)
  • use sal de longitud aleatoria como:

    private function generateSalt() { $salt = ''''; $i = rand(20, 40); //min,max length for($length = 0; $length < $i; $length++) { $salt .= chr(rand(33, 126)); } return $salt; }

  • luego genera alguna contraseña:

    private function generatePass() { $vocabulary = ''abcdefghijklmnopqrstuvwxyz0123456789''; $password = ''''; $i = rand(7,10); for($length = 0; $length < $i; $length++) { $password .= substr($vocabulary,rand(0, 35),1); } return $password.''-''; // avoid copy`n`paste :) }

  • sí, la contraseña debe ser más fuerte, pero el usuario nunca la recordará, se guardará en el navegador o se escribirá en alguna parte. Expectativas y seguridad versus realidad.

    $newSalt = $this->generateSalt(); $newPass = $this->generatePass(); $newHash = hash(''sha512'', $newPass.'':''.$newSalt); // now store hash and salt into database

  • Hay un nuevo hash, pero no ha terminado, el verdadero trabajo ha comenzado:

    1. explotación florestal
    2. protección de la sesión
    3. user, user + ip, ip temp / perm prohibiendo
    4. etc

login + logout + re / generate password: 1 o 2 tablas SQL y pocos kb de código

otras cosas sobre seguridad: muchas tablas, en realidad más de pocos kb de código


Respuesta rápida:

Utilice la biblioteca bcrypt (cuando esté lista) o password_compat de ircmaxell, es una biblioteca bcrypt.

Respuesta larga:

Esto es demasiado complejo y desactualizado para la tecnología actual. Md5 debe evitarse y simplemente la salazón no es lo suficientemente buena. Usa bcrypt y salva el dolor de cabeza.

Podrías preguntarte por qué esa biblioteca específica? Bueno, las mismas funciones estarán disponibles en php 5.5 por lo que no tendrá que cambiar ninguna codificación. La mejor de las suertes y mantenlo simple y eficiente. También lento es bueno para iniciar sesión y cosas de contraseña.

Actualización 1

@ Gumbo -> No MD5 no está roto, pero el propósito principal de los hashes como MD5 ahora y en el pasado era la comprobación de archivos (como usted sabe para verificar si el contenido del archivo puede confiarse NO en el almacenamiento de contraseñas) ya que los hashes son muy Rápido de descifrar ya que no usaría Bcrypt para verificar el contenido del archivo ya que espera entre 30 y 45 segundos ... Esto significa que un hash fue específicamente diseñado para ser leído rápidamente. Incluso un SHA512 en comparación con bcrypt sigue siendo inferior por completo. Es por eso que es imperativo impulsar algoritmos de contraseñas fuertes como Blowfish / Bcrypt en PHP. Nosotros, como usuarios y programadores, debemos expandir el conocimiento de que el almacenamiento simple de contraseñas o los algoritmos de hash de bajo nivel NO SON la respuesta, y nunca deben usarse para dicha información sensible.

Ahora al OP para realizar su transición al nuevo sistema, primero debe enviar una notificación a todos los usuarios indicando que "para su seguridad, el sistema de encriptación de contraseñas se ha actualizado ........", entonces usted les preguntaría para una actualización de contraseña por única vez, una vez que realice la actualización de contraseña usaría la función llamada password_verify y si quiere tener el control máximo de su relación de costo, use password_needs_rehash si por alguna razón elige cambiar el costo asociado con las contraseñas .

Esto no tomará un bloque masivo de código para hacer esto ya que las ganancias que recibiría en la protección de contraseña superan los aspectos negativos de tener que "recodificar" el nuevo sistema de contraseñas.

Afortunadamente, esto responde a la mayoría de las preguntas, pero no obstante la respuesta de IRCmaxell es mucho más detallada al entrar en detalles sobre diferentes algoritmos. ¡La mejor de las OP, y muchas gracias a ircmaxell!

Actualización 2

Además, ¿una contraseña almacenada como esta sería realmente crackable? ¿cómo? (Tengo curiosidad ahora)

Cualquier cosa y todo está roto es lo que mi profesor de seguridad de red me dice ... Me reí de él. Ahora que veo cosas en sus ojos ... bueno, sí ... ¡eso es absolutamente cierto!

¡Bcrypt ACTUALMENTE es el mejor método para almacenar contraseñas! Sin embargo, si nos fijamos en Scrypt que parece ser prometedor pero no es compatible con PHP. Sin embargo, cualquier cosa y todo está roto, es solo cuestión de tiempo hasta que un "geek" en un sótano se rompa Bcrypt. Pero por ahora estamos a salvo ... al igual que estamos a salvo con IPv4 nunca se está acabando ... oh, ¿espera? ...;)

Espero que esto responda a su problema que ha mencionado señor. Además, para ponerlo en contexto, mi sistema tiene un costo de 17 y tarda ~ 20 ~ ~ 30 segundos para iniciar sesión, pero cuando presenté el sistema a mi profesor y a mis clientes y por qué debería ser obligatorio, les encantó. Me sentí seguro de que estaban protegidos.


Me gustaría ir a la criptografía. Es bueno Además de incorporar una sal para proteger contra ataques de tabla arcoiris, bcrypt es una función adaptativa: con el tiempo, el recuento de iteraciones se puede aumentar para hacerlo más lento, por lo que sigue siendo resistente a los ataques de búsqueda de fuerza bruta incluso con el aumento de la potencia de cálculo.

Implementación: ¿Cómo se usa bcrypt para contraseñas hash en PHP?