Pregunta Asegure el hash y la sal para las contraseñas de PHP


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

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

Estoy usando PHP. Quiero un sistema de encriptación de contraseñas seguro y rápido. Hashing 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 una cantidad constante de caracteres.

  1. El mecanismo 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, ¿debo almacenar dos campos en la base de datos (uno usando MD5 y otro usando SHA, por ejemplo)? ¿Lo haría más seguro o inseguro?

En caso de que no fuera lo suficientemente claro, quiero saber qué funciones 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 completamente mi pregunta:

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


1049
2017-12-30 22:02


origen


Respuestas:


RENUNCIA: 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 comprobación y verificación de contraseñas.

La teoría de la respuesta sigue siendo una buena lectura.

TL; DR

Qué no hacer

  • No limite los caracteres que los usuarios pueden ingresar para las contraseñas. Solo idiotas hacen esto.
  • No limite la longitud de una contraseña. Si sus usuarios quieren una oración con supercalifragilisticexpialidocious en ella, no evite que la usen.
  • Nunca almacene la contraseña de su usuario en texto sin formato.
  • Nunca envíe una contraseña por correo electrónico a su usuario excepto cuando han perdido la suya, y usted envió una temporal.
  • Nunca, nunca registre contraseñas de ninguna manera.
  • Nunca contraseñas hash con SHA1 ¡o MD5 o incluso SHA256! Galletas modernas puede exceder los 60 y 180 mil millones hashes / second (respectivamente).
  • No mezclar bcrypt y con el crudo salida de hash (), use salida hexadecimal o base64_encódigo. (Esto se aplica a cualquier entrada que pueda tener un pícaro \0 en él, lo que puede debilitar seriamente la seguridad).

Dos

  • Usa scrypt cuando puedas; bcrypt si no puedes.
  • Usa PBKDF2 si no puedes usar bcrypt o scrypt, con hash SHA2.
  • Restablece las contraseñas de todos cuando la base de datos está en peligro.
  • 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 una buena contraseña?" Para un poco de debate).

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

El objetivo detrás de las contraseñas hash es simple: evitar el acceso malicioso a las cuentas de los usuarios al comprometer la base de datos. Por lo tanto, el objetivo del hash de contraseñas es disuadir a un hacker o cracker al costarles demasiado tiempo o dinero para calcular las contraseñas de texto sin formato. Y el tiempo / costo son los mejores elementos de disuasión en su arsenal.

Otra razón por la que desea un hash bueno y robusto en una cuenta de usuario es darle suficiente tiempo para cambiar todas las contraseñas del sistema. Si su base de datos está comprometida, necesitará suficiente tiempo para menos bloquea el sistema, si no cambia todas las contraseñas en la base de datos.

Jeremiah Grossman, CTO de Whitehat Security, declarado en su blog después de una recuperación de contraseña reciente que requirió la ruptura de fuerza bruta de su protección con contraseña:

Curiosamente, al vivir esta pesadilla, aprendí MUCHO, no sabía sobre el crackeo de contraseñas, el almacenamiento y la complejidad. He llegado a apreciar 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 todo lo que realmente puede depender es la complejidad. Esto puede ser de conocimiento común para las contraseñas y los criptoprogramas, pero para el experto promedio en Seguridad de Internet o Segmentación por Internet, lo dudo mucho.

(Énfasis mío)

Lo que hace un bueno contraseña de todos modos?

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

En resumen, la entropía es la cantidad de variación dentro de la contraseña. Cuando una contraseña solo tiene letras romanas en minúsculas, 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, es aproximadamente 96 caracteres. Eso es mucho mejor que solo letras. Un problema es que para que nuestras contraseñas sean memorables, insertamos patrones, lo que reduce la entropía. Oops!

La entropía de la contraseña es aproximado fácilmente. El uso del rango completo de caracteres ascii (aproximadamente 96 caracteres tipográficos) produce una entropía de 6.6 por carácter, que a los 8 caracteres para una contraseña es aún 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 hacen que sea más difícil descifrarla.

Hay una discusión más larga 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ñas de longitud X con X muchas letras, números, símbolos, etc., en realidad puede reducir la entropía al hacer que el esquema de contraseñas sea más predecible. Estoy de acuerdo. Randomess, tan aleatorio 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 realmente lo suficientemente buena para nuestros propósitos, así que debemos protegerlos como si estaban en Fort Knox.

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 un estándar por Linux / Unix o por servidores web, y aún no se han publicado revisiones detalladas de su algoritmo. Pero aún así, el futuro del algoritmo parece prometedor. Si está trabajando con Ruby, hay un gema scrypt eso te ayudará, y Node.js ahora tiene su propio scrypt paquete. Puedes usar Scrypt en PHP a través del Scrypt extensión o el Libsodium extensión (ambos están disponibles en PECL).

Sugiero leer la documentación para el función cripta si quieres entender cómo usar bcrypt, o encontrarte a ti mismo bueno  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 cronograma clave de blowfish, con un mecanismo de costo variable. Este último le permite aumentar el costo de la fuerza bruta de una contraseña al aumentar el calendario clave ya caro de blowfish.

Prácticas promedio

Casi no me puedo imaginar esta situación nunca más. PHPASS admite PHP 3.0.18 a 5.3, por lo que se puede utilizar en casi todas las instalaciones imaginables, y se debe usar si no saber con certeza que su entorno es compatible con bcrypt.

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

Pruebe una implementación de PDKBF2 con el número máximo de rondas que su entorno / aplicación / percepción del usuario puede 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 hacer que la operación sea más difícil de reproducir.

Prácticas futuras

Viniendo en PHP 5.5 es un biblioteca completa de protección con contraseña que abstrae cualquier trabajo de trabajar con bcrypt. Si bien la mayoría de nosotros estamos atascados con PHP 5.2 y 5.3 en la mayoría de los entornos comunes, especialmente los 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 realidad grieta una contraseña hash no existe. La única forma en que las computadoras pueden "descifrar" una contraseña es recrearla y simular el algoritmo hash utilizado para protegerla. La velocidad del hash está relacionada linealmente con su capacidad de ser forzada por fuerza bruta. Peor aún, la mayoría de los algoritmos de hash se pueden paralelizar fácilmente para realizar aún más rápido. Esta es la razón por la cual los esquemas costosos como brypt y scrypt son tan importantes.

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

Por último: no soy un 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 lo más difíciles que pueda para entrometerse, y luego, si todavía está preocupado, póngase en contacto con un pirata informático o un criptógrafo de sombrero blanco para ver qué dicen sobre su código / sistema.


892
2017-12-30 22:15



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

  • PHP 5.5 o superior: password_hash () es de buena calidad y parte del núcleo de PHP.
  • Versiones PHP más antiguas: OpenWall's phpass la biblioteca es mucho mejor que la mayoría del código personalizado: se usa en WordPress, Drupal, etc.

La mayoría de los programadores simplemente no tienen la experiencia para escribir código criptográfico de forma segura sin introducir vulnerabilidades.

Autocomprobación rápida: ¿Qué es el estiramiento de contraseñas y cuántas iteraciones debes usar? Si no sabes la respuesta, debes usar password_hash(), ya que el estiramiento de contraseñas es ahora una característica fundamental de los mecanismos de contraseñas debido a que las CPU son mucho más rápidas y el uso de GPU y FPGA descifrar contraseñas a tasas de miles de millones de conjeturas por segundo (con GPU)

Por ejemplo, puedes descifrar todas las contraseñas de Windows de 8 caracteres en 6 horas usando 25 GPU instaladas en 5 computadoras 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 arcoiris en contraseñas de Windows que se ejecutan en CPU ordinarias y son muy rápidos. Todo esto es porque Windows todavía  no sal ni estira sus contraseñas, incluso en Windows 10 - ¡No cometas el mismo error que Microsoft!

Ver también: 

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

120
2017-11-08 12:02



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


40
2017-12-30 22:18



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

Hay más explicaciones disponibles en: http://www.pivotalsecurity.com/blog/password-hashing-salt-should-it-be-random/

Recientemente tuve una discusión sobre si los hashes de las contraseñas se saldaron al azar   los bits son más seguros que el salado con adivinable o conocido   sales. Veamos: si el sistema que almacena la contraseña está comprometido como   así como el sistema que almacena la sal aleatoria, el atacante   tener acceso a hash y sal, por lo tanto, si la sal es aleatoria o   no, no importa El atacante puede generar precalculado   mesas de arcoiris para romper el hash. Aquí viene la parte interesante   no es tan trivial generar tablas pre calculadas. Déjanos tomar ejemplo   del modelo de seguridad WPA. Su contraseña WPA en realidad nunca se envía a   Punto de acceso inalámbrico. En lugar de eso, es hash con su SSID (el   nombre de la red, como Linksys, Dlink, etc.). Una muy buena explicación de cómo   esto funciona está aquí. Para recuperar la contraseña del hash, lo hará   necesita saber la contraseña y sal (nombre de la red). Iglesia de   Wifi ya tiene tablas hash precalculadas que tienen 1000 SSID principales y   alrededor de 1 millón de contraseñas El tamaño de todas las tablas es de aproximadamente 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 aquellos   ¿mesas? ¡No! .. no puede. Incluso si la contraseña es débil, las tablas   no tiene hashes para SSID a387csf3. Esta es la belleza de tener   sal al azar Disuadirá a los crackers que prosperan con cálculos previos   mesas. ¿Puede detener a un hacker determinado? Probablemente no. Pero usando   sales aleatorias proporciona una capa adicional de defensa. Mientras estamos en   este tema, veamos la ventaja adicional de almacenar al azar   sales en un sistema separado. Escenario n.º 1: los hashes de la contraseña se almacenan   en el sistema X y los valores de sal utilizados para la mezcla se almacenan en el sistema Y.   Estos valores de sal son aptos o conocidos (por ejemplo, nombre de usuario). Escenario n.º 2:   Los hashes de contraseña se almacenan en el sistema X y los valores de sal se utilizan para   hash se almacenan en el sistema Y. Estos valores de sal son aleatorios. En caso   el sistema X se ha visto comprometido, como se puede adivinar, hay un gran   ventaja de usar sal aleatoria en un sistema separado (Escenario n. ° 2).   El atacante deberá adivinar los valores de suma para poder descifrar   hashes. Si se utiliza una sal de 32 bits, 2 ^ 32 = 4.294.967.296 (aproximadamente 4,2   mil millones) se pueden requerir iteraciones para cada contraseña adivinada.


30
2018-02-12 00:52



A partir de PHP 5.5, PHP tiene funciones simples y seguras para hash y verificación de contraseñas, password_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 password_hash() se usa, genera una sal aleatoria y lo incluye en el hash generado (junto con el costo y el algoritmo utilizados). password_verify() luego lee ese hash y determina el método de sal y cifrado utilizado, y lo verifica contra la contraseña proporcionada de texto sin formato.

Proporcionar el PASSWORD_DEFAULT instruye a PHP para que use 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 potentes disponibles.

El costo creciente (que por defecto es 10) hace que el hash sea más duro que la fuerza bruta, pero también significa que la generación de hashes y la verificación de las contraseñas en su contra serán más laboriosas para la CPU de su servidor.

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


30
2017-09-21 21:33



Solo quiero señalar que PHP 5.5 incluye una API hashing de contraseña que proporciona una envoltura alrededor crypt(). Esta API simplifica significativamente la tarea de hashing, verificar y volver a generar hashes de contraseñas. El autor también ha lanzado un paquete de compatibilidad (en la 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 admite BCRYPT por ahora, pero pretende 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 a su técnica / costo de hash preferidos no invalidarán los hashes actuales, el marco Automáticamente utilizará la técnica / costo correcto al validar. También maneja la generación de una sal "segura" si no define explícitamente la suya.

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. Es útil para verificar si el hash se ajusta a su esquema actual de técnica / costo, lo que le permite volver a generar si es necesario
  • password_verify() - verifica que una contraseña coincida con un hash

Por el momento, estas funciones aceptan las contraseñas de contraseñas PASSWORD_BCRYPT y PASSWORD_DEFAULT, que también son en este momento, con la diferencia de que PASSWORD_DEFAULT "puede cambiar en versiones más nuevas de PHP cuando se admiten algoritmos de hash más nuevos y potentes". El uso de PASSWORD_DEFAULT y password_needs_rehash () al iniciar sesión (y volver a analizarlo si es necesario) debe garantizar que sus valores hash 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í porque creo que proporciona un poco más de información sobre cómo funciona y la facilidad de uso que brinda a quienes no conocen la seguridad.


25
2018-04-27 21:41



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

De manera predeterminada, usaba el cifrado más potente disponible implementado en Phpass, que es bcrypt y vuelve a otras encriptaciones hasta MD5 para proporcionar compatibilidad con versiones anteriores de frameworks 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, uno puede usar:

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

17
2018-06-26 08:05



COSAS PARA RECORDAR

Mucho se ha dicho sobre el cifrado de contraseñas para PHP, la mayoría de los cuales son muy buenos consejos, pero antes de que incluso comiences el proceso de usar PHP para el cifrado de contraseñas, asegúrate 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 no tienen valor. La mayoría de los servidores funcionan de la misma manera, tienen puertos asignados que le permiten acceder a ellos de forma remota, ya sea a través de ftp o shell. Asegúrese de cambiar el puerto predeterminado de la conexión remota que tenga activa. Al no hacer esto, de hecho has hecho que el atacante haga un paso menos para acceder a tu sistema.

USERNAME

Por todo lo que es bueno en el mundo, no use 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 esté accesible, siempre debe ser sudo solamente.

CONTRASEÑA

Le dices a tus usuarios que hagan buenas contraseñas para evitar ser pirateados, haz lo mismo. ¿Qué sentido tiene pasar todo el esfuerzo de cerrar con llave la puerta de entrada cuando tienes abierta la puerta trasera?

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 pasar por dos pasos para acceder completamente al sistema.

USUARIO

Siempre haga que su aplicación tenga su propia cuenta para acceder al DB, y solo dele los privilegios que necesitará.

Luego, tenga una cuenta de usuario separada para usted que no esté almacenada en ninguna parte 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 ninguna cuenta SERVER o DB en el mismo sistema.

PHP

CONTRASEÑA

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

HASHING

ONE HAY HASHING !!!!!!!, Nunca hash una contraseña de forma que se pueda revertir, hashes debe ser de una manera, lo que significa que no los inviertes y los comparas con la contraseña, en su lugar hash la contraseña ingresada de la misma manera y comparar los dos hashes. Esto significa que incluso si un atacante tiene 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 (password_hash, hash, etc.) pero debe seleccionar un buen algoritmo para que el hash sea efectivo. (brypt y otros similares son algoritmos decentes).

Cuando la velocidad es la clave, más lento será el más resistente a los ataques de Fuerza bruta.

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

SALAZÓN

Las contraseñas siempre se deben salar antes del hash. Salting agrega una cadena aleatoria a la contraseña para que las contraseñas similares no aparezcan igual en la base de datos. Sin embargo, si la sal no es exclusiva de cada usuario (es decir, si utiliza una sal codificada), la sal no tiene ningún valor. Porque una vez que un atacante descubre una contraseña, tiene la sal para todos.

Cuando crees una sal, asegúrate de que sea única para la contraseña que está salando, y luego guarda el hash y la sal completados en tu DB. Lo que esto hará es hacer que un atacante tenga que agrietar individualmente cada sal y hash antes de que puedan obtener acceso. 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 no encriptada se envía al servidor y si un atacante puede escuchar y acceder a ella, toda su seguridad en PHP no tiene valor. SIEMPRE transmita los datos SEGURAMENTE, esto se hace a través de SSL, pero esté cansado, incluso SSL no es perfecto (el error Heartbleed de OpenSSL es un ejemplo de esto).

También haga que el usuario cree una contraseña segura, es simple y siempre debe hacerse, el usuario estará agradecido al final.

Finalmente, no importa que las medidas de seguridad que tome nada sean 100% seguras, cuanto más avanzada sea la tecnología para 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 PHP que crea un hash y salt para una contraseña fácilmente

http://git.io/mSJqpw


13
2018-04-09 15:01



Google dice que SHA256 está disponible para PHP.

Definitivamente deberías usar una sal. Recomiendo usar bytes aleatorios (y no restringirse a caracteres y números). Como habitualmente, cuanto más tiempo elijas, más seguro, más lento se vuelve. 64 bytes deberían estar bien, supongo.


12
2017-12-30 22:20



Encontré el tema perfecto sobre este asunto aquí: https://crackstation.net/hashing-security.htm, Quería que se beneficiara de esto, aquí también está el código fuente que también brinda 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));
}
?>

8
2017-09-19 13:26