Pregunta

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

Esta pregunta, es y # 8220; doble hashing & # 8221; ¿Una contraseña menos segura que solo la hash una vez? sugiere que el hashing varias veces puede ser una buena idea, mientras que How to ¿Implementar 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. Hashear 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 menos seguro?

En caso de que no estuviera lo suficientemente claro, quiero saber qué función (es) de hash usar y cómo elegir un buen salt 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 de almacenamiento de claves, contraseñas para asp.net
¿Cómo implementaría las contraseñas con sal en Tomcat 5.5

¿Fue útil?

Solución

  

RENUNCIA DE RESPONSABILIDAD : esta respuesta se escribió en 2008.

     

Desde entonces, PHP nos ha dado password_hash y password_verify y, desde su introducción, son el hashing de contraseña recomendado & amp; método de verificación.

     

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

TL; DR

No hacer

  • No limite los caracteres que los usuarios pueden ingresar para las contraseñas. Solo los idiotas hacen esto.
  • No limites la longitud de una contraseña. Si sus usuarios desean 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 a su usuario excepto cuando hayan perdido la suya y usted haya enviado una contraseña temporal.
  • Nunca, nunca registre contraseñas de ninguna manera.
  • Nunca hash las contraseñas con SHA1 o MD5 o incluso SHA256! Los crackers modernos pueden superar los 60 y 180 billones de hashes / segundo (respectivamente).
  • No mezcle bcrypt y con el raw salida de hash () , use salida hexadecimal o base64_encode. (Esto se aplica a cualquier entrada que pueda tener un \ 0 malicioso en él, lo que puede debilitar seriamente la seguridad).

Dos

  • Usa scrypt cuando puedas; bcrypt si no puedes.
  • Use PBKDF2 si no puede usar bcrypt o scrypt, con hashes SHA2.
  • Restablecer 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? & Quot; para un debate).

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

El objetivo de las contraseñas de hash es simple: evitar el acceso malicioso a las cuentas de usuario comprometiendo la base de datos. Por lo tanto, el objetivo del hashing de contraseñas es disuadir a un pirata informático o cracker, al costarle 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 tu arsenal.

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

Jeremiah Grossman, CTO de Whitehat Security, indicado en su blog después de una recuperación de contraseña reciente que requirió la ruptura de fuerza bruta de 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 las 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 todo lo que realmente puede depender es la complejidad. Esto puede ser de conocimiento común para los profesionales de contraseñas y criptografía, pero para el experto promedio en seguridad de Internet o InfoSec, Lo dudo mucho.

(Énfasis mío)

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

Entropy . (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 es solo letras romanas en minúscula, son 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 de aproximadamente 96 caracteres. Eso es mucho mejor que solo letras. Un problema es que, para que nuestras contraseñas sean memorables, insertamos patrones & # 8212; 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 tipificables) produce una entropía de 6.6 por carácter, que en 8 caracteres para una contraseña aún es demasiado baja (52.679 bits de entropía) para 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 descifrarlas.

Hay una discusión más larga sobre la entropía de contraseñas en Crypto StackExchange sitio. Una buena búsqueda en Google también mostrará 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., realmente puede reducir la entropía al hacer el esquema de contraseña más predecible. Estoy de acuerdo. La aleatoriedad, tan aleatoriamente como sea posible, es siempre la solución más segura pero menos memorable.

Por lo que he podido decir, crear la mejor contraseña del mundo es un Catch-22. O bien no es memorable, demasiado predecible, demasiado corto, demasiados caracteres Unicode (difíciles de escribir en un dispositivo Windows / móvil), demasiado largo, etc. Ninguna contraseña es lo suficientemente buena para nuestros propósitos, por lo 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 a tiempo, pero Linux no ha considerado la adopción como estándar / 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ás trabajando con Ruby, hay una gema de cifrado que te ayudará, y Node.js ahora tiene su propio paquete scrypt . Puede usar Scrypt en PHP a través de la Scrypt o la extensión Libsodium extensión (ambos están disponibles en PECL).

Le sugiero encarecidamente que lea la documentación de la función de cifrado si desea comprender cómo utilizar bcrypt. o encontrarte a ti mismo un bueno wrapper o use algo como PHPASS para una implementación más heredada. Recomiendo un mínimo de 12 rondas de bcrypt, si no 15 a 18.

Cambié de opinión sobre el uso de bcrypt cuando me enteré de 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 mediante el aumento del costoso programa clave de blowfish.

Prácticas promedio

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

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

Pruebe una implementación de PDKBF2 con 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 de 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

Próximamente en PHP 5.5 hay una biblioteca de protección de contraseña completa que retira cualquier Dolores de trabajar con bcrypt. Mientras que la mayoría de nosotros estamos atascados con PHP 5.2 y 5.3 en los entornos más comunes, especialmente los hosts compartidos, @ircmaxell ha creado una capa de compatibilidad para la próxima API que es compatible con versiones anteriores de PHP 5.3.7.

Resumen de criptografía & amp; Descargo de responsabilidad

La potencia de cálculo necesaria para descifrar realmente no existe una contraseña con hash. La única forma en que las computadoras " crack " una contraseña es volver a crearla y simular el algoritmo de hash utilizado para asegurarla. La velocidad del hash está relacionada linealmente con su capacidad para ser forzado brutalmente. Peor aún, la mayoría de los algoritmos hash pueden ser paralelizados fácilmente para funcionar aún más rápido. Es por esto que los esquemas costosos como bcrypt 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 por adelantado . Si no lo hace, entonces podría pasar por alto el hecho de que fue atacado hasta que sea demasiado tarde ... y usted sea responsable . Para evitar esa situación, actúe paranoico para empezar. Ataca tu propio software (internamente) e intenta robar las credenciales de los usuarios, o modificar las cuentas de otros usuarios o acceder 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. 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 que las cosas sean lo más difíciles de entrometerse, y luego, si todavía está preocupado, comuníquese con un pirata informático o criptógrafo de sombrero blanco para ver qué dicen sobre su código / sistema.

Otros consejos

Una respuesta mucho más breve 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 de PHP más antiguas: la biblioteca phpass de OpenWall es mucho mejor que la mayoría de los códigos personalizados, utilizados 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 la extensión de la contraseña y cuántas iteraciones debe usar? Si no sabe la respuesta, debe usar password_hash () , ya que la extensión de la contraseña es ahora una característica crítica de los mecanismos de contraseña debido a las CPU mucho más rápidas y el uso de GPU y FPGA para descifrar contraseñas a tasas de miles de millones de conjeturas por segundo (con GPU).

Por ejemplo, puede descifra todas las contraseñas de Windows de 8 caracteres en 6 horas usando 25 GPU instaladas en 5 computadoras de escritorio. Se trata de una acción 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 se podrían usar menos GPU o descifrar más rápido con 25 GPU.

También hay muchos ataques de tabla arco iris en las contraseñas de Windows que se ejecutan en las CPU normales y son muy rápidas. Todo esto se debe a que Windows still no salva ni amplía sus contraseñas, incluso en Windows 10 : ¡no cometa el mismo error que Microsoft!

Ver también:

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

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

A partir de PHP 5.5, PHP tiene funciones simples y seguras para el hashing y la verificación de contraseñas, password_hash () y password_verify ()

$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 se usa password_hash () , genera un sal aleatorio y lo incluye en el hash generado (junto con el costo y el algoritmo usado). password_verify () luego lee ese hash y determina el método de encriptación y sal utilizado, y lo verifica con la contraseña de texto sin formato proporcionada.

Al proporcionar el PASSWORD_DEFAULT se le indica a PHP que use el algoritmo de hashing 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 forzar la fuerza bruta, pero también significa que generar hashes 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 hashes antiguos continuarán verificándose correctamente porque el algoritmo utilizado se almacena en el hash y password_verify () lo recupera.

Aunque la pregunta ha sido respondida, solo quiero reiterar que las sales utilizadas para el hashing 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/

  

Hace poco tuve una discusión sobre si los hashes de contraseña se salaban al azar   Los bits son más seguros que los salados con adivinables o conocidos.   sales. Veamos a & # 8217; s: si la contraseña de almacenamiento del sistema está comprometida como   así como el sistema que almacena la sal aleatoria, el atacante   tener acceso al hash así como a la sal, por lo tanto si la sal es aleatoria o   no, no importa. El atacante podrá generar precomputados.   Mesas arcoiris para romper el hachís. Aquí viene la parte interesante   No es tan trivial generar tablas precalculadas. Tomemos el ejemplo   del modelo de seguridad WPA. Tu contraseña WPA nunca se envía a   Punto de acceso inalámbrico. En su lugar, se tritura con su SSID (el   nombre de red, como Linksys, Dlink, etc). Una muy buena explicación de cómo.   esto funciona esta aqui Con el fin de recuperar la contraseña de hash, tendrá que   Necesito saber la contraseña, así como la sal (nombre de la red). Iglesia de   Wifi ya ha calculado previamente las tablas hash que tienen los 1000 SSID principales y   alrededor de 1 millón de contraseñas. El tamaño de todas las tablas es de unos 40 GB.   Como puedes leer en su sitio, alguien usó 15 arreglos FGPA durante 3 días   Para generar estas tablas. Suponiendo que la víctima está utilizando el SSID como   & # 8220; a387csf3 & # 8243; y la contraseña como & # 8220; 123456 & # 8243 ;, serán descifrados por aquellos   ¿mesas? ¡No! .. no puede. Incluso si la contraseña es débil, las tablas   no & # 8217; t hashes para SSID a387csf3. Esta es la belleza de tener   sal al azar Disuadirá a los crackers que prosperan en el pre-computado   mesas. ¿Puede detener a un hacker determinado? Probablemente no. Pero usando   Las sales aleatorias proporcionan una capa adicional de defensa. Mientras estamos en   este tema, vamos a discutir la ventaja adicional de almacenar al azar   Sales en un sistema separado. Escenario # 1: hashes de contraseña se almacenan   en el sistema X y los valores de sal utilizados para el hashing se almacenan en el sistema Y.   Estos valores de sal son adivinables o conocidos (por ejemplo, nombre de usuario) Escenario # 2:   Los hashes de contraseña se almacenan en el sistema X y los valores de sal utilizados para   Los hashing se almacenan en el sistema Y. Estos valores de sal son aleatorios. En caso   El sistema X se ha comprometido, como se puede adivinar, hay una gran   ventaja de usar sal aleatoria en un sistema separado (Escenario # 2).   El atacante tendrá que adivinar los valores de adición para poder romper   hashes. Si se usa una sal de 32 bits, 2 ^ 32 = 4,294,967,296 (aproximadamente 4.2   mil millones) se requerirán iteraciones para cada contraseña adivinada.

Solo quiero señalar que PHP 5.5 incluye una API de hashing de contraseñas que proporciona una envoltorio alrededor de crypt () . Esta API simplifica significativamente la tarea de hash, verificar y volver a usar hashes de contraseña. El autor también ha lanzado un paquete de compatibilidad (en la forma de un único archivo password.php que simplemente requiere para usar), para aquellos que usan PHP 5.3.7 y posteriores y quieren usar esto ahora mismo.

Por ahora solo es compatible con BCRYPT, pero pretende ser extendido fácilmente para incluir otras técnicas de hash de contraseñas y, como la técnica y el costo se almacenan como parte del hash, los cambios en su técnica / costo de hashing preferido no invalidarán los hashes actuales. , el marco de trabajo automágicamente, utilizará la técnica / costo correctos al validar. También maneja la generación de un " seguro " Sal si no define explícitamente el suyo propio.

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 / costo actual, lo que le permite repetir si es necesario
  • password_verify () : verifica que una contraseña coincida con un hash

En este 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 nuevas versiones de PHP cuando se admiten algoritmos de hashing más nuevos y más fuertes. " El uso de PASSWORD_DEFAULT y password_needs_rehash () en el inicio de sesión (y la repetición si es necesario) debe 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 ofrece a aquellos que no conocen la seguridad.

Estoy usando Phpass , que es una clase sencilla de PHP de un archivo que podría implementarse muy fácilmente en casi todos los PHP proyecto. Consulte también The H .

De forma predeterminada, usó el cifrado disponible más fuerte que se implementa en Phpass, que es bcrypt y se remonta a otros cifrados a MD5 para proporcionar compatibilidad con versiones anteriores a 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 usar:

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

THINGS TO REMEMBER

A lot has been said about Password encryption for PHP, most of which is very good advice, but before you even start the process of using PHP for password encryption make sure you have the following implemented or ready to be implemented.

SERVER

PORTS

No matter how good your encryption is if you don't properly secure the server that runs the PHP and DB all your efforts are worthless. Most servers function relatively the same way, they have ports assigned to allow you to access them remotely either through ftp or shell. Make sure that you change the default port of which ever remote connection you have active. By not doing this you in effect have made the attacker do one less step in accessing your system.

USERNAME

For all that is good in the world do not use the username admin, root or something similar. Also if you are on a unix based system DO NOT make the root account login accessible, it should always be sudo only.

PASSWORD

You tell your users to make good passwords to avoid getting hacked, do the same. What is the point in going through all the effort of locking your front door when you have the backdoor wide open.

DATABASE

SERVER

Ideally you want your DB and APPLICATION on separate servers. This is not always possible due to cost, but it does allow for some safety as the attacker will have to go through two steps to fully access the system.

USER

Always have your application have its own account to access the DB, and only give it the privileges it will need.

Then have a separate user account for you that is not stored anywhere on the server, not even in the application.

Like always DO NOT make this root or something similar.

PASSWORD

Follow the same guidelines as with all good passwords. Also don't reuse the same password on any SERVER or DB accounts on the same system.

PHP

PASSWORD

NEVER EVER store a password in your DB, instead store the hash and unique salt, I will explain why later.

HASHING

ONE WAY HASHING!!!!!!!, Never hash a password in a way that it can be reversed, Hashes should be one way, meaning you don't reverse them and compare them to the password, you instead hash the entered password the same way and compare the two hashes. This means that even if an attacker gets access to the DB he doesn't know what the actually password is, just its resulting hash. Which means more security for your users in the worst possible scenario.

There are a lot of good hashing functions out there (password_hash, hash, etc...) but you need to select a good algorithm for the hash to be effective. (bcrypt and ones similar to it are decent algorithms.)

When hashing speed is the key, the slower the more resistant to Brute Force attacks.

One of the most common mistakes in hashing is that hashes are not unique to the users. This is mainly because salts are not uniquely generated.

SALTING

Passwords should always be salted before hashed. Salting adds a random string to the password so similar passwords don't appear the same in the DB. However if the salt is not unique to each user (ie: you use a hard coded salt) than you pretty much have made your salt worthless. Because once an attacker figures out one password salt he has the salt for all of them.

When you create a salt make sure it is unique to the password it is salting, then store both the completed hash and salt in your DB. What this will do is make it so that an attacker will have to individually crack each salt and hash before they can gain access. This means a lot more work and time for the attacker.

USERS CREATING PASSWORDS

If the user is creating a password through the frontend that means it has to be sent to the server. This opens up a security issue because that means the unencrypted password is being sent to the server and if a attacker is able to listen and access that all your security in PHP is worthless. ALWAYS transmit the data SECURELY, this is done through SSL, but be weary even SSL is not flawless (OpenSSL's Heartbleed flaw is an example of this).

Also make the user create a secure password, it is simple and should always be done, the user will be grateful for it in the end.

Finally, no matter the security measures you take nothing is 100% secure, the more advanced the technology to protect becomes the more advanced the attacks become. But following these steps will make your site more secure and far less desirable for attackers to go after.

Here is a PHP class that creates a hash and salt for a password easily

http://git.io/mSJqpw

Google says SHA256 is available to PHP.

You should definitely use a salt. I'd recommend using random bytes (and not restrict yourself to characters and numbers). As usually, the longer you choose, the safer, slower it gets. 64 bytes ought to be fine, i guess.

I found perfect topic on this matter here: https://crackstation.net/hashing-security.htm, I wanted you to get benefit from it, here is source code also that provided prevention against time-based attack also.

<?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));
}
?>

In the end, double-hashing, mathematically, provides no benefit. In practice, however, it is useful for preventing rainbow table-based attacks. In other words, it is of no more benefit than hashing with a salt, which takes far less processor time in your application or on your server.

I usually use SHA1 and salt with the user ID (or some other user-specific piece of information), and sometimes I additionally use a constant salt (so I have 2 parts to the salt).

SHA1 is now also considered somewhat compromised, but to a far lesser degree than MD5. By using a salt (any salt), you're preventing the use of a generic rainbow table to attack your hashes (some people have even had success using Google as a sort of rainbow table by searching for the hash). An attacker could conceivably generate a rainbow table using your salt, so that's why you should include a user-specific salt. That way, they will have to generate a rainbow table for each and every record in your system, not just one for your entire system! With that type of salting, even MD5 is decently secure.

SHA1 and a salt should suffice (depending, naturally, on whether you are coding something for Fort Knox or a login system for your shopping list) for the foreseeable future. If SHA1 isn't good enough for you, use SHA256.

The idea of a salt is to throw the hashing results off balance, so to say. It is known, for example, that the MD5-hash of an empty string is d41d8cd98f00b204e9800998ecf8427e. So, if someone with good enough a memory would see that hash and know that it's the hash of an empty string. But if the string is salted (say, with the string "MY_PERSONAL_SALT"), the hash for the 'empty string' (i.e. "MY_PERSONAL_SALT") becomes aeac2612626724592271634fb14d3ea6, hence non-obvious to backtrace. What I'm trying to say, that it's better to use any salt, than not to. Therefore, it's not too much of an importance to know which salt to use.

There are actually websites that do just this - you can feed it a (md5) hash, and it spits out a known plaintext that generates that particular hash. If you would get access to a database that stores plain md5-hashes, it would be trivial for you to enter the hash for the admin to such a service, and log in. But, if the passwords were salted, such a service would become ineffective.

Also, double-hashing is generally regarded as bad method, because it diminishes the result space. All popular hashes are fixed-length. Thus, you can have only a finite values of this fixed length, and the results become less varied. This could be regarded as another form of salting, but I wouldn't recommend it.

ok in the fitsy we need salt salt must be unique so let generate it

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

also we need the hash I`m using sha512 it is the best and it is in php

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

so now we can use this functions to generate safe password

// 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);

now we need to save in database our $hash_psw variable value and $salt variable

and for authorize we will use same steps...

it is the best way to safe our clients passwords...

P.s. for last 2 steps you can use your own algorithm... but be sure that you can generate this hashed password in the future when you need to authorize user...

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top