PHP 5.5 Password Hashing API (BCRYPT)


En artículos pasados hemos revisado algunos de los cambios más importantes en las recientes versiones de PHP 5.5.X. Si recuerdan abordamos generadores, trabajo con arreglos entre otras. Hoy les traigo otro de los agregados más importantes en los recientes realeases.

La seguridad básica de cualquier sistema web incluye las máximas AAA establecidas, ellas son Authentication-Authorization-Accounting, donde la autenticación es siempre el primer paso para lograr una autorización y niveles de seguridad adecuados para explotar los recursos de un sistema. ¿Pero dónde se guardan las claves y cómo? Es una pregunta que muchos saben pero, ¿estaremos aplicando los métodos más adecuados para ello?

Las claves de los usuarios siempre se guardan encriptadas en la tabla de usuario, utilizando un SALT determinado que trabaje siempre a favor de su complejidad. Algoritmos como md5() o sha1() han sido utilizados durante algún tiempo pero ha quedado demostrado que son débiles y usando las técnicas adecuadas muy fáciles de romper. Para PHP desde hace ya algunas versiones acepta como buenas prácticas el uso de las funciones bcrypt(). Fuerte y altamente confiable es lo recomendado pero, ¿por qué todavía muchos desarrolladores no lo utilizan? Hay que reconocer que su complejidad trabaja en contra de su popularidad y frecuentemente su mal uso genera errores de programación que pueden ser fatales en los temas de seguridad.

Los desarrolladores de PHP presentan una nueva API que usando como base a bcrypt() simplifica todas sus posibilidades a solo cuatro funciones.

  • password_hash() – Crea el HASH de la clave dada
  • password_verify() – Verifica el HASH
  • password_needs_rehash() – Esta función comprueba si el hash facilitado implementa el algoritmo y opciones proporcionadas. Si no, asume que el hash necesita volver a ser generado
  • password_get_info() – Devuelve información sobre el hash proporcionado

password_hash()

La función password_hash() simplifica todo el trabajo de encriptación, toma 3 parámetros siendo los 2 primeros de ellos obligatorios. Por defecto el SALT y el COST son generados automáticamente por ellos aunque por supuesto pueden ser establecidos.

  $hash = password_hash($passwod, PASSWORD_DEFAULT); // El SALT y el COST son generados automáticamente

  $options = [
      'salt' => genera_salt(), 
      'cost' => 12
  ];
  $hash = password_hash($password, PASSWORD_BCRYPT, $options); // Cambiamos el algoritmo a usar para generar los HASH

password_verify()

Una vez generado el HASH presenta una manera muy fácil de verificarlo a partir de la clave proporcionada. Devuelve TRUE si la contraseña y el HASH coinciden y falso de lo contrario. No es necesario establecer el SALT pues ya es parte del HASH generado anteriormente.

  $hash = '$2y$07$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq'; // El HASH puede haber estado guardado en la base de datos

  if (password_verify('rasmuslerdorf', $hash)) {
      echo '¡La contraseña es válida!';
  } else {
      echo 'La contraseña no es válida.';
  }

password_needs_rehash()

En cambio, supongamos que necesitamos modificar el SALT o el COST usados para el HASH obtenido anteriormente. Esto puede darse en los casos de querer mejorar la seguridad mediante estas opciones. No tenemos la necesidad de generar nuevamente el HASH con la función password_hash(). Comprueba si el HASH facilitado implementa el algoritmo y opciones proporcionadas. Si no, asume que necesita volver a ser generado.

  if (password_needs_rehash($hash, PASSWORD_DEFAULT, ['cost' => 12])) {
      // El HASH necesita ser regenerado si no fue creado con el costo o algoritmo especificados
      $hash = password_hash($password, PASSWORD_DEFAULT, ['cost' => 12]);
  }

password_get_info()

Devuelve información sobre el HASH proporcionado. Cuando se le pasa un HASH válido creado con un algoritmo soportado por password_hash(), esta función devolverá un array con información sobre el mismo.

Esta nueva API nos abstrae de los niveles de complejidad necesarios para implementar con bcrypt(). Tengan en cuenta, la base es bcrypt() así que estamos por el buen camino. El único inconveniente en este caso es solamente actualizar tu versión de PHP y todo lo que esto conlleva en las aplicaciones en producción, pero cuando te decidas utiliza no solo esta nueva cualidad, sino todas las demás de las que hemos hablado. PHP 5.5.X si es mejor.

Latest posts by Leroy Ley (see all)