password_hash en PHP: Cómo Hashear Contraseñas con bcrypt

password_hash() es la función nativa de PHP para hashear contraseñas de forma segura. Genera el hash usando bcrypt (o Argon2) con un salt aleatorio incluido dentro del propio hash, y luego se comprueba con password_verify(). Es la forma recomendada desde PHP 5.5: nunca uses md5() ni sha1() para contraseñas.
El uso mínimo y seguro es este:
// Al registrar: guardas el hash, nunca la contraseña en texto plano.
$hash = password_hash($password, PASSWORD_DEFAULT);
// Al iniciar sesión: comparas la contraseña contra el hash guardado.
if (password_verify($password, $hash)) {
// La contraseña es correcta.
}Con eso ya tienes un login seguro. El resto del artículo explica qué pasa por dentro y cómo afinarlo.
Por qué no usar md5() ni sha1()
Es común ver código viejo que hashea contraseñas con md5:
md5('password'); // 5f4dcc3b5aa765d61d8327deb882cf99El problema es que md5 y sha1 son rápidos y sin salt: una GPU prueba miles de millones de combinaciones por segundo, y existen tablas (rainbow tables) que revierten esos hashes al instante. Para contraseñas necesitas justo lo contrario: un algoritmo lento y con salt, que es lo que te da password_hash().
La firma de password_hash()
Según la documentación oficial, la función recibe la contraseña, el algoritmo y un array opcional de opciones:
password_hash(string $password, string|int|null $algo, array $options = []): stringAlgoritmos disponibles
PASSWORD_DEFAULT: el algoritmo recomendado por PHP en cada versión. Hoy es bcrypt, pero puede cambiar en el futuro, así que el hash resultante puede crecer en longitud. Guarda la columna comoVARCHAR(255).PASSWORD_BCRYPT: fuerza bcrypt. Genera hashes de 60 caracteres que empiezan por$2y$.PASSWORD_ARGON2ID: Argon2id, disponible si PHP se compiló con soporte para Argon2. Es una buena alternativa moderna a bcrypt.
El parámetro cost
El cost controla cuánto trabajo cuesta calcular el hash: a mayor cost, más lento (y más resistente a fuerza bruta). En bcrypt el valor por defecto es 10, y subió a 12 en PHP 8.4.
$hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);Súbelo solo hasta donde tu servidor pueda calcular un hash en una fracción de segundo razonable. No definas el salt a mano: la opción salt se marcó como obsoleta en PHP 7.0 y se eliminó en PHP 8.0. password_hash() ya genera un salt criptográficamente seguro por ti.
Verificar y rehashear
Para comprobar una contraseña usas password_verify(), que vuelve a calcular el hash internamente y lo compara sin filtrar información de tiempo:
if (password_verify($password, $hashGuardado)) {
// Acceso concedido.
}Como el algoritmo recomendado y el cost cambian con las versiones de PHP, conviene rehashear las contraseñas cuando el usuario inicia sesión, usando password_needs_rehash():
if (password_verify($password, $hashGuardado)) {
if (password_needs_rehash($hashGuardado, PASSWORD_DEFAULT)) {
$nuevoHash = password_hash($password, PASSWORD_DEFAULT);
// Guarda $nuevoHash en la base de datos.
}
}Así tus hashes se mantienen al día sin pedirle al usuario que cambie su contraseña.
Resumen
- Usa
password_hash($password, PASSWORD_DEFAULT)para hashear ypassword_verify()para comprobar. - Nunca uses
md5nisha1para contraseñas, ni guardes la contraseña en texto plano. - No generes el
saltmanualmente: ya viene incluido en el hash. - Guarda el hash en una columna
VARCHAR(255)y rehashea conpassword_needs_rehash()cuando haga falta.
Lecturas recomendadas: documentación oficial de password_hash.