PHP
Funciones de hash de contraseña
Buscar..
Introducción
A medida que los servicios web más seguros evitan el almacenamiento de contraseñas en formato de texto plano, los lenguajes como PHP proporcionan varias funciones hash (no descifrables) para admitir el estándar de la industria más seguro. Este tema proporciona documentación para el hashing adecuado con PHP.
Sintaxis
-
string password_hash ( string $password , integer $algo [, array $options ] )
-
boolean password_verify ( string $password , string $hash )
-
boolean password_needs_rehash ( string $hash , integer $algo [, array $options ] )
-
array password_get_info ( string $hash )
Observaciones
Antes de PHP 5.5, puede usar el paquete de compatibilidad para proporcionar las funciones password_*
. Se recomienda encarecidamente que utilice el paquete de compatibilidad si puede hacerlo.
Con o sin el paquete de compatibilidad, la funcionalidad correcta de Bcrypt a través de crypt()
basa en PHP 5.3.7+. De lo contrario, debe restringir las contraseñas a conjuntos de caracteres solo ASCII.
Nota: si usa PHP 5.5 o una versión inferior, está usando una versión no compatible de PHP que ya no recibe actualizaciones de seguridad. Actualice tan pronto como sea posible, puede actualizar sus hashes de contraseña posteriormente.
Selección de algoritmo
Algoritmos seguros
- bcrypt es su mejor opción siempre que use el estiramiento de teclas para aumentar el tiempo de cálculo del hash, ya que hace que los ataques de fuerza bruta sean extremadamente lentos .
- argon2 es otra opción que estará disponible en PHP 7.2 .
Algoritmos inseguros
Los siguientes algoritmos de hashing son inseguros o no aptos para el propósito y, por lo tanto , no deben utilizarse . Nunca fueron adecuados para el hashing de contraseñas, ya que están diseñados para resúmenes rápidos en lugar de hashes de contraseñas lentas y difíciles de aplicar.
Si utiliza alguno de ellos , incluso las sales, debe cambiar a uno de los algoritmos de seguridad recomendados lo antes posible .
Algoritmos considerados inseguros:
- MD4 - ataque de colisión encontrado en 1995
- MD5 - ataque de colisión encontrado en 2005
- SHA-1 - ataque de colisión demostrado en 2015
Algunos algoritmos pueden usarse de manera segura como algoritmo de resumen de mensajes para probar la autenticidad, pero nunca como algoritmo de hashing de contraseña :
- SHA-2
- SHA-3
Tenga en cuenta que los hashes fuertes como SHA256 y SHA512 son ininterrumpidos y robustos, sin embargo, en general es más seguro usar las funciones hash bcrypt o argon2 , ya que los ataques de fuerza bruta contra estos algoritmos son mucho más difíciles para las computadoras clásicas.
Determine si un hash de contraseña existente puede actualizarse a un algoritmo más fuerte
Si está utilizando el método PASSWORD_DEFAULT
para permitir que el sistema elija el mejor algoritmo para cifrar sus contraseñas, ya que la fuerza predeterminada aumenta, es posible que desee volver a borrar las contraseñas antiguas a medida que los usuarios inician sesión
<?php
// first determine if a supplied password is valid
if (password_verify($plaintextPassword, $hashedPassword)) {
// now determine if the existing hash was created with an algorithm that is
// no longer the default
if (password_needs_rehash($hashedPassword, PASSWORD_DEFAULT)) {
// create a new hash with the new default
$newHashedPassword = password_hash($plaintextPassword, PASSWORD_DEFAULT);
// and then save it to your data store
//$db->update(...);
}
}
?>
Si las funciones password_ * no están disponibles en su sistema (y no puede usar el paquete de compatibilidad vinculado en las observaciones a continuación), puede determinar el algoritmo y usarlo para crear el hash original en un método similar al siguiente:
<?php
if (substr($hashedPassword, 0, 4) == '$2y$' && strlen($hashedPassword) == 60) {
echo 'Algorithm is Bcrypt';
// the "cost" determines how strong this version of Bcrypt is
preg_match('/\$2y\$(\d+)\$/', $hashedPassword, $matches);
$cost = $matches[1];
echo 'Bcrypt cost is '.$cost;
}
?>
Creando un hash de contraseña
Cree hashes de contraseñas utilizando password_hash()
para usar el hash estándar o la derivación de claves más recomendables de la industria. Al momento de escribir, el estándar es bcrypt , lo que significa que PASSWORD_DEFAULT
contiene el mismo valor que PASSWORD_BCRYPT
.
$options = [
'cost' => 12,
];
$hashedPassword = password_hash($plaintextPassword, PASSWORD_DEFAULT, $options);
El tercer parámetro no es obligatorio .
El valor del 'cost'
debe elegirse en función del hardware de su servidor de producción. Incrementarlo hará que la contraseña sea más costosa de generar. Cuanto más costoso es generar, más tiempo tomará cualquiera que intente descifrarlo para generarlo también. Lo ideal es que el costo sea lo más alto posible, pero en la práctica debe establecerse para que no disminuya la velocidad demasiado. En algún lugar entre 0.1 y 0.4 segundos estaría bien. Utilice el valor predeterminado si tiene dudas.
En PHP inferior a 5.5.0, las funciones password_*
no están disponibles. Debe usar el paquete de compatibilidad para sustituir esas funciones. Tenga en cuenta que el paquete de compatibilidad requiere PHP 5.3.7 o superior o una versión que $2y
solución de $2y
fixport (como la que proporciona RedHat).
Si no puede usarlos, puede implementar el hashing de contraseñas con crypt()
Como password_hash()
se implementa como un envoltorio alrededor de la función crypt()
, no necesita perder ninguna funcionalidad.
// this is a simple implementation of a bcrypt hash otherwise compatible
// with `password_hash()`
// not guaranteed to maintain the same cryptographic strength of the full `password_hash()`
// implementation
// if `CRYPT_BLOWFISH` is 1, that means bcrypt (which uses blowfish) is available
// on your system
if (CRYPT_BLOWFISH == 1) {
$salt = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM);
$salt = base64_encode($salt);
// crypt uses a modified base64 variant
$source = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
$dest = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$salt = strtr(rtrim($salt, '='), $source, $dest);
$salt = substr($salt, 0, 22);
// `crypt()` determines which hashing algorithm to use by the form of the salt string
// that is passed in
$hashedPassword = crypt($plaintextPassword, '$2y$10$'.$salt.'$');
}
Sal para el hash de contraseña
A pesar de la fiabilidad del algoritmo de cripta, todavía existe una vulnerabilidad frente a las tablas de arco iris . Esa es la razón, por eso se recomienda usar sal .
Un salt es algo que se agrega a la contraseña antes de hacer hashing para hacer que la cadena fuente sea única. Dadas dos contraseñas idénticas, los hashes resultantes también serán únicos, porque sus sales son únicas.
Una sal aleatoria es una de las piezas más importantes de la seguridad de su contraseña. Esto significa que incluso con una tabla de búsqueda de hashes de contraseña conocida, un atacante no puede hacer coincidir el hash de contraseña del usuario con los hashes de contraseña de la base de datos, ya que se ha utilizado un salt aleatorio. Debes usar sales siempre aleatorias y criptográficamente seguras. Lee mas
Con password_hash()
bcrypt
algorithm, la sal de texto sin formato se almacena junto con el hash resultante, lo que significa que el hash se puede transferir a través de diferentes sistemas y plataformas y aún puede compararse con la contraseña original.
Incluso cuando esto no se recomienda, puede usar la opción de salt
para definir su propia sal aleatoria.
$options = [
'salt' => $salt, //see example below
];
Importante Si omite esta opción, password_hash () generará un valor aleatorio de sal para cada hash de contraseña. Este es el modo de operación previsto.
La opción salt ha sido desaprobada a partir de PHP 7.0.0. Ahora se prefiere usar simplemente la sal que se genera de forma predeterminada.
Verificando una contraseña contra un hash
password_verify()
es la función incorporada provista (a partir de PHP 5.5) para verificar la validez de una contraseña contra un hash conocido.
<?php
if (password_verify($plaintextPassword, $hashedPassword)) {
echo 'Valid Password';
}
else {
echo 'Invalid Password.';
}
?>
Todos los algoritmos de hash admitidos almacenan información que identifica qué hash se usó en el hash mismo, por lo que no es necesario indicar con qué algoritmo está utilizando para codificar la contraseña de texto simple.
Si las funciones password_ * no están disponibles en su sistema (y no puede usar el paquete de compatibilidad vinculado en las observaciones a continuación), puede implementar la verificación de contraseña con la función crypt()
. Tenga en cuenta que deben tomarse precauciones específicas para evitar los ataques de tiempo .
<?php
// not guaranteed to maintain the same cryptographic strength of the full `password_hash()`
// implementation
if (CRYPT_BLOWFISH == 1) {
// `crypt()` discards all characters beyond the salt length, so we can pass in
// the full hashed password
$hashedCheck = crypt($plaintextPassword, $hashedPassword);
// this a basic constant-time comparison based on the full implementation used
// in `password_hash()`
$status = 0;
for ($i=0; $i<strlen($hashedCheck); $i++) {
$status |= (ord($hashedCheck[$i]) ^ ord($hashedPassword[$i]));
}
if ($status === 0) {
echo 'Valid Password';
}
else {
echo 'Invalid Password';
}
}
?>