Hash y salt seguros para contraseñas PHP

Actualmente se dice que MD5 es parcialmente inseguro. Teniendo esto en cuenta, me gustaría saber qué mecanismo utilizar para la protección con contraseña.

Esta pregunta, ¿Es el "doble hash" una contraseña menos segura que solo usarla una vez? sugiere que aplicar hash varias veces puede ser una buena idea, mientras que ¿Cómo implementar la protección con contraseña para archivos individuales? sugiere usar sal.

Estoy usando PHP. Quiero un sistema de cifrado de contraseña seguro y rápido. Hacer un hash de una contraseña un millón de veces puede ser más seguro, pero también más lento. ¿Cómo lograr un buen equilibrio entre velocidad y seguridad? Además, prefiero que el resultado tenga un número constante de caracteres.

  1. El mecanismo de hash debe estar disponible en PHP
  2. Debe ser seguro
  3. Puede usar sal (en este caso, ¿todas las sales son igualmente buenas? ¿Hay alguna forma de generar buenas sales?)

Además, ¿debería almacenar dos campos en la base de datos (uno con MD5 y otro con SHA, por ejemplo)? ¿Lo haría más seguro o más inseguro?

En caso de que no haya sido lo suficientemente claro, quiero saber qué función (es) de hash usar y cómo elegir una buena sal para tener un mecanismo de protección de contraseña seguro y rápido.

Preguntas relacionadas que no cubren mi pregunta:

¿Cuál es la diferencia entre SHA y MD5 en PHP?
Cifrado de contraseña simple
Métodos seguros para almacenar claves, contraseñas para asp.net
¿Cómo implementarías contraseñas saladas en Tomcat 5.5?

preguntado el 30 de diciembre de 08 a las 23:12

openwall.com/phpass también es muy buena biblioteca -

Md5 ahora es completamente inseguro -

@NSAwesomeGuy Eso depende de para qué lo estés usando. Es trivial combinar contraseñas MD5 sin sal o simplemente por la fuerza bruta, claro, pero con un salado decente sigue siendo extremadamente poco práctico construir una tabla de arco iris para descifrar rápidamente conjuntos de contraseñas, y la fuerza bruta no es una esperanza. -

PHP 5.5+ tiene un hash de contraseña seguro incorporado php.net/manual/en/function.password-hash.php -

14 Respuestas

RENUNCIA DE RESPONSABILIDAD: Esta respuesta fue escrita en 2008.

Desde entonces, PHP nos ha dado password_hash y password_verify y, desde su introducción, son el método recomendado de control y hash de contraseñas.

Sin embargo, la teoría de la respuesta sigue siendo una buena lectura.

TL; DR

No hacer

  • No limite los caracteres que los usuarios pueden ingresar para las contraseñas. Solo los idiotas hacen esto.
  • No limite la longitud de una contraseña. Si sus usuarios quieren una oración con supercalifragilisticexpialidocious en ella, no les impida usarla.
  • No elimine ni escape HTML y caracteres especiales en la contraseña.
  • Nunca almacene su contraseña de usuario en texto plano.
  • Nunca envíe una contraseña por correo electrónico a su usuario excepto cuando han perdido el suyo, y tú enviaste uno temporal.
  • Nunca, nunca registre contraseñas de ninguna manera.
  • Nunca hash contraseñas con SHA1 o MD5 o incluso SHA256! Galletas modernas puede superar los 60 y 180 mil millones de hashes / segundo (respectivamente).
  • No mezclar bcrypt y con el crudo salida de hash (), use salida hexadecimal o base64_encode. (Esto se aplica a cualquier entrada que pueda tener un error \0 en él, lo que puede debilitar gravemente la seguridad).

Espalda

  • Utilice scrypt cuando pueda; bcrypt si no puede.
  • Use PBKDF2 si no puede usar bcrypt o scrypt, con hashes SHA2.
  • Restablezca las contraseñas de todos cuando la base de datos se vea comprometida.
  • Implemente una longitud mínima razonable de 8-10 caracteres, además de requerir al menos 1 letra mayúscula, 1 letra minúscula, un número y un símbolo. Esto mejorará la entropía de la contraseña, lo que a su vez hará que sea más difícil de descifrar. (Consulte la sección "¿Qué hace que una contraseña sea buena?" Para un debate).

¿Por qué hash contraseñas de todos modos?

El objetivo detrás de las contraseñas hash es simple: prevenir el acceso malicioso a las cuentas de los usuarios comprometiendo la base de datos. Por lo tanto, el objetivo del hash de contraseñas es disuadir a un pirata informático o pirata informático, costándole demasiado tiempo o dinero para calcular las contraseñas de texto sin formato. Y el tiempo y el costo son los mejores elementos disuasorios de su arsenal.

Otra razón por la que desea un hash bueno y sólido en las cuentas de un usuario es darle tiempo suficiente para cambiar todas las contraseñas en el sistema. Si su base de datos está comprometida, necesitará tiempo suficiente para menos bloquee el sistema, si no, cambie todas las contraseñas de la base de datos.

Jeremiah Grossman, director de tecnología de Whitehat Security, declarado en el blog de White Hat Security después de una reciente recuperación de contraseña que requirió romper por fuerza bruta su protección de contraseña:

Curiosamente, al vivir esta pesadilla, aprendí MUCHO que no sabía sobre el descifrado, el almacenamiento y la complejidad de contraseñas. He llegado a comprender por qué el almacenamiento de contraseñas es mucho más importante que la complejidad de las contraseñas. Si no sabe cómo se almacena su contraseña, entonces de todo lo que realmente puede depender es de la complejidad. Esto podría ser de conocimiento común para los profesionales de contraseñas y criptografía, pero para el experto promedio en InfoSec o en seguridad web, lo dudo mucho.

(El énfasis es mío.)

¿Qué hace que una buena contraseña de todos modos?

Entropía. (No es que suscriba completamente el punto de vista de Randall).

En resumen, la entropía es cuánta variación hay dentro de la contraseña. Cuando una contraseña tiene solo letras romanas en minúscula, eso es solo 26 caracteres. Eso no es mucha variación. Las contraseñas alfanuméricas son mejores, con 36 caracteres. Pero permitir mayúsculas y minúsculas, con símbolos, tiene aproximadamente 96 caracteres. Eso es mucho mejor que solo letras. Un problema es que para hacer que nuestras contraseñas sean memorables, insertamos patrones, lo que reduce la entropía. ¡UPS!

La entropía de la contraseña es aproximado fácilmente. El uso de la gama completa de caracteres ascii (aproximadamente 96 caracteres que se pueden escribir) produce una entropía de 6.6 por carácter, que con 8 caracteres para una contraseña sigue siendo demasiado baja (52.679 bits de entropía) para la seguridad futura. Pero la buena noticia es que: las contraseñas más largas y las contraseñas con caracteres Unicode realmente aumentan la entropía de una contraseña y la hacen más difícil de descifrar.

Hay una discusión más extensa sobre la entropía de contraseñas en el Crypto StackExchange sitio. Una buena búsqueda en Google también arrojará muchos resultados.

En los comentarios hablé con @popnoodles, quien señaló que hacer cumplir una política de contraseña de X longitud con X muchas letras, números, símbolos, etc., puede reducir la entropía haciendo que el esquema de contraseña sea más predecible. Estoy de acuerdo. La aleatoriedad, tan verdaderamente aleatoria como sea posible, es siempre la solución más segura pero menos memorable.

Por lo que he podido decir, hacer la mejor contraseña del mundo es un Catch-22. O no es memorable, demasiado predecible, demasiado corto, demasiados caracteres Unicode (difíciles de escribir en un dispositivo Windows / Mobile), demasiado largo, etc. Ninguna contraseña es lo suficientemente buena para nuestros propósitos, por lo que debemos protegerlos como si fueran estaban en Fort Knox.

Las Mejores Prácticas

Bcrypt y Scrypt son las mejores prácticas actuales. Scrypt será mejor que bcrypt en el tiempo, pero no ha sido adoptado como estándar por Linux / Unix o por servidores web, y aún no se han publicado revisiones en profundidad de su algoritmo. Pero aún así, el futuro del algoritmo parece prometedor. Si está trabajando con Ruby, hay una gema de scrypt que te ayudará, y Node.js ahora tiene su propio Scrypt paquete. Puede usar Scrypt en PHP a través del Scrypt extensión o la Libsodio extensión (ambos están disponibles en PECL).

Recomiendo encarecidamente leer la documentación para el función de cripta si quieres entender cómo usar bcrypt, o encontrarte un buena envoltura o usa algo como PHPASS para una implementación más heredada. Recomiendo un mínimo de 12 rondas de bcrypt, si no de 15 a 18.

Cambié de opinión sobre el uso de bcrypt cuando supe que bcrypt solo usa el programa clave de Blowfish, con un mecanismo de costo variable. Este último le permite aumentar el costo de forzar una contraseña al aumentar el ya costoso programa de claves de Blowfish.

Prácticas medias

Ya casi no puedo imaginar esta situación. PHPASS es compatible con PHP 3.0.18 a 5.3, por lo que se puede usar en casi todas las instalaciones imaginables, y debe usarse si no lo hace saber con certeza que su entorno es compatible con bcrypt.

Pero suponga que no puede usar bcrypt o PHPASS en absoluto. ¿Entonces que?

Pruebe una implementación de PDKBF2 con número máximo de rondas que su entorno / aplicación / percepción del usuario pueda tolerar. El número más bajo que recomendaría es 2500 rondas. Además, asegúrese de usar hash_hmac () si está disponible para dificultar la reproducción de la operación.

Prácticas futuras

Viniendo en PHP 5.5 es un biblioteca de protección de contraseña completa que abstrae cualquier molestia de trabajar con bcrypt. Si bien la mayoría de nosotros estamos atrapados con PHP 5.2 y 5.3 en la mayoría de los entornos comunes, especialmente hosts compartidos, @ircmaxell ha construido un capa de compatibilidad para la próxima API que es compatible con PHP 5.3.7.

Resumen de criptografía y descargo de responsabilidad

La potencia computacional requerida para realmente grieta no existe una contraseña hash. La única forma en que las computadoras pueden "descifrar" una contraseña es recrearla y simular el algoritmo hash que se utiliza para protegerla. La velocidad del hash está relacionada linealmente con su capacidad de ser forzado. Peor aún, la mayoría de los algoritmos hash se pueden paralelizar fácilmente para funcionar aún más rápido. Es por eso que los esquemas costosos como bcrypt y scrypt son tan importantes.

No es posible prever todas las amenazas o vías de ataque, por lo que debe hacer su mejor esfuerzo para proteger a sus usuarios. en la delantera. Si no lo hace, es posible que incluso se pierda el hecho de que fue atacado hasta que sea demasiado tarde ... y tu eres responsable. Para evitar esa situación, actúa paranoico para empezar. Ataque su propio software (internamente) e intente robar las credenciales de usuario, o modifique las cuentas de otros usuarios o acceda a sus datos. Si no prueba la seguridad de su sistema, no puede culpar a nadie más que a usted mismo.

Por último: no soy criptógrafo. Todo lo que he dicho es mi opinión, pero creo que se basa en el buen sentido común ... y mucha lectura. Recuerde, sea lo más paranoico posible, haga las cosas tan difíciles de entrometerse como sea posible y luego, si todavía está preocupado, comuníquese con un hacker de sombrero blanco o un criptógrafo para ver qué dicen sobre su código / sistema.

respondido 30 nov., 19:23

un secreto no ayuda, ya que se supone que la base de datos de su contraseña es secreta de todos modos; si pueden conseguir esa base de datos, también pueden encontrar cualquier secreto que esté usando. sin embargo, es importante que la sal sea aleatoria. - Frankodwyer

@ pulga malvada, no voy a discutir contigo. Simplemente señalando lo enrevesada y compleja que es esta área de nuestro trabajo. Sigo esperando que me enseñen las mejores prácticas para configurar el sistema de gestión de contenido de un sitio web pequeño. Todavía estoy aprendiendo aquí. ... cada vez que leo algo que tiene sentido, pronto noto otras 5 publicaciones que lo contradicen. que vueltas y vueltas se vuelven vertiginosas rápidamente :) - m42

Interesante revisión. ¿Es la ID de usuario (digamos, un BIGINT de incremento automático) una buena opción? ¿O como no es aleatorio, no es bueno? Además, tendré que almacenar el nonce para cada usuario en la base de datos ... ¿La clave del sitio + nonce + HMAC proporciona una seguridad mejorada significativa sobre un hash salado (con ID de usuario) iterado varias veces? De manera similar, ¿iterar HMAC varias veces es bueno para la seguridad? - luiscubal

Enviar una contraseña temporal por correo electrónico que requiera que el usuario la cambie la primera vez que la use y enviar un enlace "seguro" por correo electrónico que le permita establecer su contraseña son igualmente riesgosos. En cualquier caso, cualquiera que intercepte el correo electrónico puede acceder a la cuenta siempre que utilice el enlace o la contraseña antes de que lo haga el destinatario previsto. - Tim Gautier

@RobertK Al expandir el conjunto de caracteres, sí, aumenta, PERO al forzar que todas las contraseñas sigan las reglas, disminuye la cantidad de opciones posibles. Digamos que alguien iba a obtener una contraseña por fuerza bruta. Al decirles que la contraseña del usuario tiene 1 letra mayúscula, 1 letra minúscula, un número y un símbolo, significa que la cantidad de intentos que necesitan es significativamente menor. Al permitir que el usuario decida lo que quiere, el hacker tiene que esforzarse más. - Popnoodles

Una respuesta mucho más corta y segura: no escriba su propio mecanismo de contraseña en absoluto, utilice un mecanismo probado y comprobado.

  • PHP 5.5 o superior: contraseña_hash () es de buena calidad y forma parte del núcleo de PHP.
  • PHP 4.x (obsoleto): OpenWall's phpass La biblioteca es mucho mejor que la mayoría de los códigos personalizados: se usa en WordPress, Drupal, etc.

La mayoría de los programadores simplemente no tienen la experiencia para escribir código relacionado con criptografía de forma segura sin introducir vulnerabilidades.

Autoprueba rápida: ¿Qué es el estiramiento de contraseñas y cuántas iteraciones debería utilizar? Si no sabe la respuesta, debe usar password_hash(), ya que el estiramiento de contraseñas es ahora una característica crítica de los mecanismos de contraseñas debido a CPU mucho más rápidas y al uso de GPU y FPGA para descifrar contraseñas a tasas de miles de millones de conjeturas por segundo (con GPU).

Por ejemplo, puede descifrar todas las contraseñas de Windows de 8 caracteres en 6 horas utilizando 25 GPU instaladas en 5 PC de escritorio. Esto es fuerza bruta, es decir, enumerar y verificar cada contraseña de Windows de 8 caracteres, incluidos los caracteres especiales y no es un ataque de diccionario. Eso fue en 2012, a partir de 2018, podría usar menos GPU o crackear más rápido con 25 GPU.

También hay muchos ataques de tabla de arco iris en contraseñas de Windows que se ejecutan en CPU normales y son muy rápidos. Todo esto se debe a que Windows posible no sale ni se estira sus contraseñas, incluso en Windows 10 - ¡No cometa el mismo error que hizo Microsoft!

Ver también:

  • excelente respuesta con más sobre por qué password_hash() or phpass son la mejor manera de hacerlo.
  • buen artículo de blog dando los 'factores de trabajo' recomendados (número de iteraciones) para los algoritmos principales, incluidos bcrypt, scrypt y PBKDF2.

respondido 19 nov., 20:11

pero estos sistemas son más conocidos y tal vez ya estén comprometidos. pero es mejor que hacer el tuyo propio cuando no sabes lo que haces. - JqueryToAddNumbers

Re "estos sistemas son más conocidos y tal vez ya estén comprometidos" - no hay ninguna razón por la cual un sistema bien diseñado para la autenticación deba convertirse "ya comprometido" solo porque es más conocido. Las bibliotecas como phpass están escritas por expertos y muchas personas las revisan en detalle; el hecho de que sean bien conocidas va acompañado de una revisión detallada por parte de diferentes personas y es más probable que signifique que son seguras. - RichVel

"no escriba su propio mecanismo de contraseña", pero los verdaderamente paranoicos querrán escribir la suya propia para minimizar la probabilidad de que la NSA tenga una puerta trasera. - PP.

@PP: las posibilidades de que un algoritmo de hash de contraseña revisado por pares tenga una puerta trasera de la NSA son muy bajas, en mi opinión. Las posibilidades de que alguien que no sea un verdadero experto en criptografía escriba un nuevo mecanismo de hash de contraseña sin otras vulnerabilidades es mucho menor. Y la aplicación web típica usa solo hash MD5 o SHA-1, lo cual es terrible, incluso el excelente libro Essential PHP Security de Chris Shiflett recomienda MD5 ... - RichVel

phpass NO es la mejor manera de hacerlo. Nunca lo ha sido y probablemente nunca lo será. Revisé el código hace varios años y NO es seguro en Windows ni en ninguna plataforma donde / dev / urandom no esté disponible. NO sigue las mejores prácticas cuando se trata de seguridad, utilizando una combinación de md5 () y microtime () cuando debería terminar la aplicación en lugar de hacer afirmaciones falsas sobre la seguridad. No ha visto ninguna actualización desde que revisé el código a pesar de que PHP mismo avanzó en el espacio de seguridad con bcrypt en el núcleo. Manténgase LEJOS de phpass. - Cubículo Suave

No almacenaría la contraseña hash de dos formas diferentes, porque entonces el sistema es al menos tan débil como el más débil de los algoritmos hash en uso.

Respondido el 17 de enero de 13 a las 18:01

no para el hash de contraseñas. el atacante solo necesita romper un hash para recuperar la contraseña. el punto es discutible de todos modos, ya que ni MD5 ni SHA1 tienen interrupciones prácticas disponibles en el escenario de la contraseña. - Frankodwyer

lo siento, leí mal su respuesta como recomendando el uso de dos hashes ... de hecho, tiene razón. El uso de dos hash debilita el sistema en el caso de la contraseña, ya que solo necesitan romper el hash más débil. - Frankodwyer

A partir de PHP 5.5, PHP tiene funciones simples y seguras para hacer hash y verificar contraseñas, contraseña_hash () y Contraseña verificada()

$password = 'anna';
$hash = password_hash($password, PASSWORD_DEFAULT);
$expensiveHash = password_hash($password, PASSWORD_DEFAULT, array('cost' => 20));

password_verify('anna', $hash); //Returns true
password_verify('anna', $expensiveHash); //Also returns true
password_verify('elsa', $hash); //Returns false

Cuando te password_hash() se utiliza, genera una sal aleatoria y la incluye en el hash generado (junto con el costo y el algoritmo utilizado). password_verify() luego lee ese hash y determina el método de cifrado y sal utilizado, y lo verifica con la contraseña de texto sin formato proporcionada.

Proporcionando la PASSWORD_DEFAULT indica a PHP que utilice el algoritmo hash predeterminado de la versión instalada de PHP. Exactamente qué algoritmo significa que está destinado a cambiar con el tiempo en futuras versiones, de modo que siempre será uno de los algoritmos más sólidos disponibles.

El aumento del costo (que por defecto es 10) hace que el hash sea más difícil de usar por fuerza bruta, pero también significa que generar hash y verificar las contraseñas contra ellos será más trabajo para la CPU de su servidor.

Tenga en cuenta que aunque el algoritmo de hash predeterminado puede cambiar, los hash antiguos continuarán verificándose bien porque el algoritmo utilizado se almacena en el hash y password_verify() lo capta.

Respondido 25 ago 15, 22:08

Aunque la pregunta ha sido respondida, solo quiero reiterar que las sales utilizadas para el hash deben ser aleatorias y no similares a la dirección de correo electrónico como se sugiere en la primera respuesta.

Más explicación está disponible en- http://www.pivotalsecurity.com/blog/password-hashing-salt-should-it-be-random/

Recientemente tuve una discusión sobre si los hash de contraseña salados con bits aleatorios son más seguros que el salado con sales adivinables o conocidas. Veamos: si el sistema que almacena la contraseña está comprometido, así como el sistema que almacena la sal aleatoria, el atacante tendrá acceso tanto al hash como a la sal, por lo que si la sal es aleatoria o no, no importa. El atacante puede generar tablas de arco iris precalculadas para descifrar el hash. Aquí viene la parte interesante: no es tan trivial generar tablas precalculadas. Tomemos un ejemplo del modelo de seguridad WPA. En realidad, su contraseña WPA nunca se envía al punto de acceso inalámbrico. En cambio, tiene un hash con su SSID (el nombre de la red, como Linksys, Dlink, etc.). Una muy buena explicación de cómo funciona esto está aquí. Para recuperar la contraseña del hash, deberá conocer la contraseña y el nombre de la red (salt). Church of Wifi ya tiene tablas hash precalculadas que tienen los 1000 SSID superiores y aproximadamente 1 millón de contraseñas. El tamaño de todas las tablas es de unos 40 GB. Como puede leer en su sitio, alguien usó 15 matrices FGPA durante 3 días para generar estas tablas. Suponiendo que la víctima esté usando el SSID como "a387csf3" y la contraseña como "123456", ¿será descifrado por esas tablas? ¡No! .. no puede. Incluso si la contraseña es débil, las tablas no tienen hash para SSID a387csf3. Ésta es la belleza de tener sal al azar. Disuadirá a los crackers que prosperan con tablas precalculadas. ¿Puede detener a un hacker determinado? Probablemente no. Pero el uso de sales aleatorias proporciona una capa adicional de defensa. Mientras estamos en este tema, analicemos la ventaja adicional de almacenar sales aleatorias en un sistema separado. Escenario n. ° 1: los hash de contraseña se almacenan en el sistema X y los valores de sal utilizados para el hash se almacenan en el sistema Y. Estos valores de sal se pueden adivinar o se conocen (por ejemplo, nombre de usuario) Escenario n. ° 2: los hash de contraseña se almacenan en el sistema X y los valores de sal se utilizan para el hash se almacena en el sistema Y. Estos valores de sal son aleatorios. En caso de que el sistema X se haya visto comprometido, como puede adivinar, existe una gran ventaja de usar sal aleatoria en un sistema separado (Escenario n. ° 2). El atacante deberá adivinar valores de suma para poder descifrar hashes. Si se utiliza un salt de 32 bits, se pueden requerir 2 ^ 32 = 4,294,967,296 (aproximadamente 4.2 mil millones) de iteraciones para cada contraseña adivinada.

Respondido el 27 de junio de 12 a las 20:06

Incluso si el atacante obtiene la sal, una cadena "sitesalt: usersalt: password" sigue siendo resistente a las tablas precalculadas, ya que el atacante necesita generar las tablas para cada usuario (por lo que el ataque se vuelve mucho más lento), a menos que, por supuesto, un usuario específico está siendo el objetivo ... - luiscubal

Con respecto a "Incluso si el atacante obtiene la sal, una cadena" sitesalt: usersalt: password "sigue siendo resistente a las tablas precalculadas", totalmente de acuerdo. Mi punto es que sitesalt si se hace aleatorio y extenso, hará que el sistema sea más seguro de lo que (sitesalt) es predecible. He visto a algunas personas que recomiendan el uso de la identificación de correo electrónico, etc., como sal, y lo desaconsejo. - Gaurav Kumar

Te perdiste lo que escribí originalmente. Dije que usara un nonce aleatorio, almacenado con el registro, MÁS la dirección de correo electrónico. La adición de la dirección de correo electrónico genera entropía adicional para que el hacker trabaje. Desde entonces, he reescrito mi respuesta a favor de bcrypt. - Robert k

Solo quiero señalar que PHP 5.5 incluye un API de hash de contraseña que proporciona una envoltura alrededor crypt(). Esta API simplifica significativamente la tarea de hash, verificación y repetición de hash de contraseña. El autor también ha publicado un paquete de compatibilidad (en forma de un único archivo password.php que simplemente require para usar), para aquellos que usan PHP 5.3.7 y posterior y quieren usar esto ahora mismo.

Solo es compatible con BCRYPT por ahora, pero su objetivo es extenderse fácilmente para incluir otras técnicas de hash de contraseñas y, debido a que la técnica y el costo se almacenan como parte del hash, los cambios en su técnica / costo de hash preferido no invalidarán los hash actuales, el marco. Automágicamente, usará la técnica / costo correcto al validar. También maneja la generación de un salt "seguro" si no define explícitamente el suyo.

La API expone cuatro funciones:

  • password_get_info() - devuelve información sobre el hash dado
  • password_hash() - crea un hash de contraseña
  • password_needs_rehash() : comprueba si el hash dado coincide con las opciones dadas. Útil para verificar si el hash se ajusta a su técnica / esquema de costos actual, lo que le permite repetir si es necesario
  • password_verify() - verifica que una contraseña coincide con un hash

Por el momento, estas funciones aceptan las constantes de contraseña PASSWORD_BCRYPT y PASSWORD_DEFAULT, que son sinónimos en este momento, con la diferencia de que PASSWORD_DEFAULT "puede cambiar en las versiones más recientes de PHP cuando se admiten algoritmos hash más nuevos y más fuertes". El uso de PASSWORD_DEFAULT y password_needs_rehash () al iniciar sesión (y repetir el hash si es necesario) debería garantizar que sus hashes sean razonablemente resistentes a los ataques de fuerza bruta con poco o ningún trabajo para usted.

EDITAR: Me acabo de dar cuenta de que esto se menciona brevemente en la respuesta de Robert K. Dejaré esta respuesta aquí, ya que creo que proporciona un poco más de información sobre cómo funciona y la facilidad de uso que proporciona para aquellos que no conocen la seguridad.

Respondido 06 Jul 14, 18:07

Estoy usando Phpass que es una clase PHP simple de un solo archivo que podría implementarse muy fácilmente en casi todos los proyectos PHP. Ver también El h.

De forma predeterminada, usó el cifrado más fuerte disponible que se implementa en Phpass, que es bcrypt y recurre a otros cifrados hasta MD5 para proporcionar compatibilidad con versiones anteriores de marcos como Wordpress.

El hash devuelto podría almacenarse en la base de datos tal como está. El uso de muestra para generar hash es:

$t_hasher = new PasswordHash(8, FALSE);
$hash = $t_hasher->HashPassword($password);

Para verificar la contraseña, se puede utilizar:

$t_hasher = new PasswordHash(8, FALSE);
$check = $t_hasher->CheckPassword($password, $hash);

Respondido el 26 de junio de 12 a las 12:06

COSAS PARA RECORDAR

Se ha dicho mucho sobre el cifrado de contraseñas para PHP, la mayoría de los cuales son muy buenos consejos, pero antes de comenzar el proceso de uso de PHP para el cifrado de contraseñas, asegúrese de tener lo siguiente implementado o listo para ser implementado.

SERVIDOR

PUERTOS

No importa qué tan bueno sea su cifrado si no protege adecuadamente el servidor que ejecuta PHP y DB, todos sus esfuerzos son inútiles. La mayoría de los servidores funcionan relativamente de la misma manera, tienen puertos asignados para permitirle acceder a ellos de forma remota a través de ftp o shell. Asegúrese de cambiar el puerto predeterminado de cualquier conexión remota que tenga activa. Al no hacer esto, ha hecho que el atacante dé un paso menos para acceder a su sistema.

NOMBRE DE USUARIO

Por todo lo bueno del mundo, no uses el nombre de usuario admin, root o algo similar. Además, si está en un sistema basado en Unix, NO haga que el inicio de sesión de la cuenta raíz sea accesible, siempre debe ser solo sudo.

CONTRASEÑA

Les dice a sus usuarios que creen buenas contraseñas para evitar ser pirateados, hagan lo mismo. ¿Cuál es el punto de pasar por todo el esfuerzo de cerrar la puerta de entrada cuando tienes la puerta trasera abierta de par en par?

BASE DE DATOS

SERVIDOR

Lo ideal es que desee su DB y APLICACIÓN en servidores separados. Esto no siempre es posible debido al costo, pero permite cierta seguridad, ya que el atacante tendrá que seguir dos pasos para acceder completamente al sistema.

USUARIO

Siempre haga que su aplicación tenga su propia cuenta para acceder a la base de datos y solo dele los privilegios que necesitará.

Luego, tenga una cuenta de usuario separada para usted que no esté almacenada en ningún lugar del servidor, ni siquiera en la aplicación.

Como siempre, NO hagas esta raíz o algo similar.

CONTRASEÑA

Siga las mismas pautas que con todas las buenas contraseñas. Tampoco reutilice la misma contraseña en ningún SERVIDOR o cuentas de base de datos en el mismo sistema.

PHP

CONTRASEÑA

NUNCA almacene una contraseña en su base de datos, en su lugar almacene el hash y la sal única, explicaré por qué más adelante.

HASHING

HASHING DE UNA MANERA !!!!!!!, Nunca hash una contraseña de una manera que se pueda revertir, los hash deben ser unidireccionales, lo que significa que no los invierte y los compara con la contraseña, en su lugar, hash la contraseña ingresada de la misma manera y compare los dos hashes. Esto significa que incluso si un atacante obtiene acceso a la base de datos, no sabe cuál es la contraseña real, solo el hash resultante. Lo que significa más seguridad para sus usuarios en el peor escenario posible.

Hay muchas buenas funciones de hash por ahí (password_hash, hash, etc ...) pero debe seleccionar un buen algoritmo para que el hash sea efectivo. (bcrypt y otros similares son algoritmos decentes).

Cuando la velocidad de hash es la clave, cuanto más lenta, más resistente a los ataques de fuerza bruta.

Uno de los errores más comunes en el hash es que los hash no son exclusivos de los usuarios. Esto se debe principalmente a que las sales no se generan de forma única.

SALAZÓN

Las contraseñas siempre deben tener sal antes de hash. Salting agrega una cadena aleatoria a la contraseña para que las contraseñas similares no aparezcan iguales en la base de datos. Sin embargo, si la sal no es única para cada usuario (es decir, si usa una sal codificada), entonces prácticamente ha hecho que su sal no tenga valor. Porque una vez que un atacante descubre una sal de contraseña, tiene la sal para todas.

Cuando cree una sal, asegúrese de que sea única para la contraseña que está salando, luego almacene tanto el hachís como la sal completa en su base de datos. Lo que esto hará es que un atacante tenga que romper individualmente cada sal y picadillo antes de poder acceder. Esto significa mucho más trabajo y tiempo para el atacante.

USUARIOS QUE CREAN CONTRASEÑAS

Si el usuario está creando una contraseña a través de la interfaz, eso significa que debe enviarse al servidor. Esto abre un problema de seguridad porque eso significa que la contraseña sin cifrar se envía al servidor y si un atacante puede escuchar y acceder, toda su seguridad en PHP no tiene valor. SIEMPRE transmita los datos de forma SEGURA, esto se hace a través de SSL, pero esté cansado, incluso SSL no es impecable (el defecto Heartbleed de OpenSSL es un ejemplo de esto).

También haz que el usuario cree una contraseña segura, es simple y siempre debe hacerse, el usuario se lo agradecerá al final.

Finalmente, independientemente de las medidas de seguridad que tome, nada es 100% seguro, cuanto más avanzada se vuelve la tecnología a proteger, más avanzados se vuelven los ataques. Pero seguir estos pasos hará que su sitio sea más seguro y mucho menos deseable para los atacantes.

Aquí hay una clase de PHP que crea un hash y sal para una contraseña fácilmente

http://git.io/mSJqpw

Respondido 07 Jul 14, 23:07

Debería eliminar SHA512 de su lista de algoritmos hash decentes, porque es demasiado rápido. Úselo solo en combinación con PBKDF2. Si bien BCrypt se basa en blowfish, blowfish en sí mismo es un algoritmo de cifrado, no de hash. - martinstoeckli

¿Cómo se almacena la sal aleatoria en la base de datos? Creo que no lo hash (no puede usarse para verificación) ni lo almacena en claro (no hay beneficios reales si el atacante puede leer la base de datos). Entonces, ¿cómo lo haces? - Iazel

wmfrancia escribió: "Salting agrega una cadena aleatoria a la contraseña para que contraseñas similares no aparezcan iguales en la base de datos". Esto no tiene sentido para mi. Los hash en la base de datos ya parecerán diferentes porque esa es una propiedad de las funciones hash. - H2ONaCl

wmfancia escribió con respecto a una sal constante: "una vez que un atacante descubre una sal de contraseña, tiene la sal para todas". Lo mismo se puede decir que si el pirata informático descubre qué campo DB es la sal, tiene las sales para todos ellos. Dado que una sal constante probablemente no estaría en la base de datos, eso es algo bueno acerca de una sal constante. - H2ONaCl

Por supuesto, estos comentarios no sugieren que una sal aleatoria por usuario no sea mejor que una sal por aplicación. Es mejor. - H2ONaCl

Google dice que SHA256 está disponible para PHP.

Definitivamente deberías usar sal. Recomendaría usar bytes aleatorios (y no limitarse a caracteres y números). Como de costumbre, cuanto más tiempo elija, más seguro y más lento se volverá. 64 bytes deberían estar bien, supongo.

Respondido el 31 de diciembre de 08 a las 01:12

64 bits deberían ser suficientes para cualquiera? - Konerak

@Konerak, volvería a esto después de 20 años. :) Pero sí, SHA256 está disponible. Si desea saber qué tan seguro es SHA256, es posible que desee verificar esto: security.stackexchange.com/questions/90064/… - Vincent Edward Gedaria Binua

Al final, el doble hash, matemáticamente, no proporciona ningún beneficio. En la práctica, sin embargo, es útil para prevenir ataques basados ​​en tablas de arco iris. En otras palabras, no es más beneficioso que hacer hash con una sal, que requiere mucho menos tiempo de procesador en su aplicación o en su servidor.

Respondido el 31 de diciembre de 08 a las 01:12

El hash múltiple también protege contra el diccionario y los ataques de fuerza bruta, es decir, simplemente hace que se tarde más en calcular. - Frankodwyer

El doble hash no le dará una ventaja significativa, pero las iteraciones de hash de varias rondas siguen siendo una defensa viable contra los ataques de diccionario y fuerza bruta. Los hash de contraseña de fuerza industrial usan más de 1000 rondas. El PBKDF5 de PKCS # 1 sugiere un mínimo de 1000 rondas. - Berk D. Demir

Encontré el tema perfecto sobre este asunto aquí: https://crackstation.net/hashing-security.htm, Quería que se beneficiara de él, aquí está el código fuente que también proporciona prevención contra ataques basados ​​en el tiempo.

<?php
/*
 * Password hashing with PBKDF2.
 * Author: havoc AT defuse.ca
 * www: https://defuse.ca/php-pbkdf2.htm
 */

// These constants may be changed without breaking existing hashes.
define("PBKDF2_HASH_ALGORITHM", "sha256");
define("PBKDF2_ITERATIONS", 1000);
define("PBKDF2_SALT_BYTES", 24);
define("PBKDF2_HASH_BYTES", 24);

define("HASH_SECTIONS", 4);
define("HASH_ALGORITHM_INDEX", 0);
define("HASH_ITERATION_INDEX", 1);
define("HASH_SALT_INDEX", 2);
define("HASH_PBKDF2_INDEX", 3);

function create_hash($password)
{
    // format: algorithm:iterations:salt:hash
    $salt = base64_encode(mcrypt_create_iv(PBKDF2_SALT_BYTES, MCRYPT_DEV_URANDOM));
    return PBKDF2_HASH_ALGORITHM . ":" . PBKDF2_ITERATIONS . ":" .  $salt . ":" . 
        base64_encode(pbkdf2(
            PBKDF2_HASH_ALGORITHM,
            $password,
            $salt,
            PBKDF2_ITERATIONS,
            PBKDF2_HASH_BYTES,
            true
        ));
}

function validate_password($password, $good_hash)
{
    $params = explode(":", $good_hash);
    if(count($params) < HASH_SECTIONS)
       return false; 
    $pbkdf2 = base64_decode($params[HASH_PBKDF2_INDEX]);
    return slow_equals(
        $pbkdf2,
        pbkdf2(
            $params[HASH_ALGORITHM_INDEX],
            $password,
            $params[HASH_SALT_INDEX],
            (int)$params[HASH_ITERATION_INDEX],
            strlen($pbkdf2),
            true
        )
    );
}

// Compares two strings $a and $b in length-constant time.
function slow_equals($a, $b)
{
    $diff = strlen($a) ^ strlen($b);
    for($i = 0; $i < strlen($a) && $i < strlen($b); $i++)
    {
        $diff |= ord($a[$i]) ^ ord($b[$i]);
    }
    return $diff === 0; 
}

/*
 * PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt
 * $algorithm - The hash algorithm to use. Recommended: SHA256
 * $password - The password.
 * $salt - A salt that is unique to the password.
 * $count - Iteration count. Higher is better, but slower. Recommended: At least 1000.
 * $key_length - The length of the derived key in bytes.
 * $raw_output - If true, the key is returned in raw binary format. Hex encoded otherwise.
 * Returns: A $key_length-byte key derived from the password and salt.
 *
 * Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt
 *
 * This implementation of PBKDF2 was originally created by https://defuse.ca
 * With improvements by http://www.variations-of-shadow.com
 */
function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
{
    $algorithm = strtolower($algorithm);
    if(!in_array($algorithm, hash_algos(), true))
        die('PBKDF2 ERROR: Invalid hash algorithm.');
    if($count <= 0 || $key_length <= 0)
        die('PBKDF2 ERROR: Invalid parameters.');

    $hash_length = strlen(hash($algorithm, "", true));
    $block_count = ceil($key_length / $hash_length);

    $output = "";
    for($i = 1; $i <= $block_count; $i++) {
        // $i encoded as 4 bytes, big endian.
        $last = $salt . pack("N", $i);
        // first iteration
        $last = $xorsum = hash_hmac($algorithm, $last, $password, true);
        // perform the other $count - 1 iterations
        for ($j = 1; $j < $count; $j++) {
            $xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
        }
        $output .= $xorsum;
    }

    if($raw_output)
        return substr($output, 0, $key_length);
    else
        return bin2hex(substr($output, 0, $key_length));
}
?>

Respondido el 19 de Septiembre de 13 a las 17:09

Nos das una solución sin ningún uso sin uso - Michael

Por lo general, uso SHA1 y salt con la ID de usuario (o alguna otra información específica del usuario) y, a veces, también uso una sal constante (por lo que tengo 2 partes de la sal).

SHA1 ahora también se considera algo comprometido, pero en un grado mucho menor que MD5. Al usar una sal (cualquier sal), está evitando el uso de un genérico mesa arcoiris para atacar tus hashes (algunas personas incluso han tenido éxito usando Google como una especie de tabla de arcoíris al buscar el hash). Un atacante podría generar una tabla de arcoíris usando su sal, por eso debe incluir una sal específica del usuario. De esa manera, tendrán que generar una tabla de arco iris para todos y cada uno de los registros de su sistema, ¡no solo uno para todo su sistema! Con ese tipo de salazón, incluso MD5 es decentemente seguro.

Respondido el 31 de diciembre de 08 a las 01:12

la sal constante no es una gran idea ... probablemente no sea un defecto fatal, pero debilita innecesariamente el esquema. - Frankodwyer

MD5 y SHA1 son rápidos, por lo que este es un mal diea. - CódigosInChaos

SHA1 y una sal debería ser suficiente (dependiendo, naturalmente, de si estás codificando algo para Fort Knox o un sistema de inicio de sesión para su lista de compras) en el futuro previsible. Si SHA1 no es lo suficientemente bueno para usted, use SHA256.

La idea de una sal es desequilibrar los resultados del hash, por así decirlo. Se sabe, por ejemplo, que el hash MD5 de una cadena vacía es d41d8cd98f00b204e9800998ecf8427e. Entonces, si alguien con una memoria lo suficientemente buena pudiera ver ese hash y saber que es el hash de una cadena vacía. Pero si la cuerda está salada (digamos, con la cuerda "MY_PERSONAL_SALT"), el hash de la 'cadena vacía' (es decir,"MY_PERSONAL_SALT") se convierte en aeac2612626724592271634fb14d3ea6, por lo tanto, no es obvio rastrear. Lo que estoy tratando de decir, que es mejor usar cualquier sal, que no. Por lo tanto, no es muy importante saber el cual sal para usar.

En realidad hay sitios web que hacen exactamente esto - puede alimentarlo con un hash (md5), y escupe un texto plano conocido que genera ese hash en particular. Si tuviera acceso a una base de datos que almacena md5-hashes simples, sería trivial para usted ingresar el hash para el administrador de dicho servicio e iniciar sesión. Pero, si las contraseñas fueran saladas, dicho servicio se convertiría en ineficaz.

Además, el doble hash generalmente se considera un método incorrecto, ya que disminuye el espacio de resultados. Todos los hash populares son de longitud fija. Por lo tanto, solo puede tener valores finitos de esta longitud fija y los resultados serán menos variados. Esto podría ser considerado como otra forma de salazón, pero no lo recomendaría.

Respondido el 31 de diciembre de 08 a las 01:12

El sitio de destino no debe contener nada demasiado sensible (no es un banco), pero aún así prefiero tenerlo protegido. - luiscubal

El doble hash no reduce el espacio de resultados. El hash iterativo es un control común contra los ataques de diccionario y de fuerza bruta (los ralentiza mucho más de lo que ralentiza la comprobación de contraseñas). - Frankodwyer

@frankodwyer: sí, está mal. sha1(sha1($foo)) reduce efectivamente el espacio de salida, porque cualquier colisión de la función interna se convertirá automáticamente en una colisión de la externa. La degradación es lineal, pero sigue siendo una preocupación. Los métodos de hash iterativos retroalimentan los datos en cada ronda, como $hash = sha1(sha1($salt . $password) . $salt). Pero eso todavía no es bueno ... Quédate con PBKDF2 o Bcrypt ... - ircmaxell

ok, en el fity necesitamos sal, la sal debe ser única, así que vamos a generarla.

   /**
     * Generating string
     * @param $size
     * @return string
     */
    function Uniwur_string($size){
        $text = md5(uniqid(rand(), TRUE));
        RETURN substr($text, 0, $size);
    }

también necesitamos el hash Estoy usando sha512 es el mejor y está en php

   /**
     * Hashing string
     * @param $string
     * @return string
     */
    function hash($string){
        return hash('sha512', $string);
    }

así que ahora podemos usar estas funciones para generar una contraseña segura

// generating unique password
$password = Uniwur_string(20); // or you can add manual password
// generating 32 character salt
$salt = Uniwur_string(32);
// now we can manipulate this informations

// hashin salt for safe
$hash_salt = hash($salt);
// hashing password
$hash_psw = hash($password.$hash_salt);

ahora necesitamos guardar en la base de datos nuestro valor de la variable $ hash_psw y la variable $ salt

y para autorizar usaremos los mismos pasos ...

es la mejor manera de proteger las contraseñas de nuestros clientes ...

Ps para los últimos 2 pasos, puede usar su propio algoritmo ... pero asegúrese de poder generar esta contraseña hash en el futuro cuando necesite autorizar al usuario ...

Respondido 08 Oct 15, 07:10

Esta pregunta trataba sobre hashes para contraseñas. 1 ejecución de sha512 (incluso si está salado) se considera que no es lo suficientemente bueno para la protección con contraseña. (también que RNG no es criptográficamente seguro, por lo que su uso para la generación de contraseñas es arriesgado). - luiscubal

No tienes idea de lo que estás haciendo. Lea las respuestas principales en esta publicación y podrá ver por qué su código no solo es inseguro, sino que no tiene sentido. - críptico ツ

está bien. mi código no es seguro. déjame saber por qué estás usando en tus algoritmos ony sha256 ??? Sé que sha512 es el mejor, ¿por qué no usarlo? - Shalvasoft

@shalvasoft sha512 es bastante bueno para el hash de propósito general, pero la protección con contraseña requiere hash con propiedades muy específicas ("ser lento" es extrañamente un Cosa Buena, por ejemplo, y sha512 es bastante rápido). Algunas personas han usado sha512 como un bloque de construcción para crear funciones de hash de contraseñas, pero hoy en día el enfoque recomendado es "usar bcrypt y mantener un ojo en scrypt". - luiscubal

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.