Cómo encriptar contraseñas en PHP - Hielo Creativo
Califica este contenido
[Total: 0 Promedio: 0]

Encriptar u ocultar mensajes, es algo muy común en aplicaciones de todo tipo. Cuando aprendemos un lenguaje de programación nuevo, es una de esas cosas fundamentales que debemos saber. PHP no es la excepción y dado que es un lenguaje de programación muy utilizado para construir aplicaciones web, entonces es necesario conocer como lo hace.

Antes de continuar, es importante resaltar la necesidad de encriptar no solo contraseñas, sino cualquier dato que consideremos necesario e importante, ya que guardarlo a texto plano, puede comprometer seriamente la seguridad de nuestras aplicaciones, datos y usuarios.

Funciones inseguras para encriptar contraseñas en PHP

Se consideran inseguras aquellas funciones que emplean algoritmo de cifrado algo antiguos o que ya han sido “rotos”, es decir, crackeados por alguien, haciéndolos obviamente inseguros. En PHP, esas funciones son MD5 y SHA1 que utilizan los algoritmos homónimos.

En el caso de MD5, dependiendo de la complejidad de la contraseña, se dice que es posible descifrarla en menos de una hora con un rango promedio de 3650 millones de cálculos por segundo. Eso significa que MD5, es el más inseguro de los algoritmos soportados.

Utilizando SHA1, es posible hacerlo en casi el mismo tiempo (de nuevo, dependiendo de la complejidad de la contraseña) pero con un rango promedio de 1360 millones de cálculos por segundo, así que tampoco es exactamente la mejor opción.

Encriptar contraseñas con MD5

Pese a que no es recomendable, por supuesto que es posible utilizar dicha función, quizá para aplicaciones que no estarán en red o por pura diversión. En todo caso, su sintaxis es la siguiente:

md5(string $string, bool $binary = false): string

Siendo que:

  • $string: Es la cadena de texto a cifrar
  • $binary: Si es true el hash resultado es un binario de 16 caracteres, caso contrario es de 32 caracteres.

Observe el siguiente ejemplo:

$laClave = "SoyUnaClav3#";
$res = md5($laClave, false);
echo "Clave de 32bits: $res <br />";
$res = md5($laClave, true);
echo "Clave binaria de 16bits: $res <br />";

El cual produce el siguiente resultado:

Cifrar contraseñas con MD5 en PHP - Hielo Creativo

Encriptar contraseñas con SHA1

El algoritmo SHA1 establecido en el RFC3174, es un estándar que fue adoptado por el gobierno de Estados Unidos para el manejo de su información federal, sin embargo en el año 2017 ellos mismo desaconsejaron el uso de este algoritmo, ya que irónicamente la existencia de dispositivos con mayor poder de cómputo lo hace fácil de atacar y romper. La sintaxis en PHP es la siguiente:

sha1(string $str, bool $raw_output = false): string

Siendo que:

  • $str – Es la cadena a cifrar
  • $raw_output – Si vale true se devuelve una cadena binaria de 20 caracteres, de lo contrario se regresa un hexadecimal de 40 caracteres.

Observa el ejemplo:

$res = sha1($laClave, false);
echo "Clave hexadecimal de 40bits: $res <br />";
$res = sha1($laClave, true);
echo "Clave binaria de 20bits: $res <br />";

El cual produce el siguiente resultado:

Cifrar contraseñas con SHA1 en PHP - Hielo Creativo

Funciones de hash para encriptar contraseñas

Un hash es un algoritmo matemático que transforma datos en una nueva serie de caracteres con una determinada longitud. SHA1 y MD5 son funciones de hash bastante débiles, por lo que para generar un hash más confiable y potente, podemos utilizar algunas de las funciones de hash que PHP trae incluidas.

Aunque son varias las funciones que se pueden utilizar. En este artículo solo cubriremos las siguientes funciones:

  • hash: Genera un valor hash
  • hash_algos: Entrega una lista con los algoritmos soportados
  • hash_equals: Realiza una comparación de hash segura
  • hash_file: Genera un hash usando el contenido de un archivo

Cómo generar un valor hash

La función hash ofrece más opciones para encriptar contraseñas mucho más estables y seguras que MD5 y SHA1. La principal ventaja que nos da está función, es la posibilidad de elegir el algoritmo matemático con que podemos generar el hash. Su sintaxis es la siguiente:

hash(string $algo, string $data, bool $raw_output = false): string

Siendo que:

  • $algo – Es el algoritmo a utilizar
  • $data – Es el valor a cifrar
  • $raw_output – Si es true, el resultado será un binario, en caso contrario será un hexadecimal.

Por ejemplo, aquí tenemos algunos algoritmos diferentes a MD5 y SHA1:

$res = hash("sha256", $laClave, false);
echo "Clave con SHA256: $res <br />";
$res = hash("snefru", $laClave, false);
echo "Clave con Snefru: $res <br />";
$res = hash("ripemd320", $laClave, false);
echo "Clave con Ripemd320: $res <br />";

Siendo estas sus correspondientes salidas:

Cifrar contraseñas con la función hash en PHP - Hielo Creativo

Mostrar la lista de algoritmos soportados

Para mostrar la lista completa de algoritmos soportados por las funciones de hash, se utiliza la función hash_algos, la cual no tiene argumentos y regresa como resultado un array con la lista completa. Por ejemplo:

print_r(hash_algos());

Y da como resultado:

Lista de algoritmos de cifrado en PHP - Hielo Creativo

Comparación segura de hashes

La función hash_equals regresa un valor booleano que puede ser falso o verdadero al comparar el string original con otro hash y ver si son iguales (true) o no (false). Su sintaxis es la siguiente:

hash_equals(string $known_string, string $user_string): bool

Donde:

  • $known_string – Es el string original
  • $user_string – Es el hash para comparar

Por ejemplo:

$original = hash("sha256", $laClave, false);
$comparar = hash("sha256", "SoyOtro#ash3", false);
if(hash_equals($original, $comparar))
   echo "Ambos hash coinciden <br />";
else echo "Los hash no coinciden <br />";

Por supuesto que dará false, ya que ambas hash no coinciden.

Comprobación de hash en PHP - Hielo Creativo

Generando un hash a partir de un archivo

Por diferentes razones, es posible que se necesita crear un hash desde un archivo de texto. Para lograr esto, se utiliza la función hash_file. Su sintaxis es la siguiente:

hash_file(string $algo, string $filename, bool $raw_output = false): string

En donde:

  • $algo – Es el algoritmo a utilizar
  • $filename – Es la URL del archivo a utilizar
  • $raw_output – Si es true, será una salida de datos binarios. Caso contrario será en hexadecimal.

Por ejemplo:

file_put_contents('ejemplo.txt', 'Soy un texto random dentro de un archivo');
echo hash_file('sha512', 'ejemplo.txt');

Genera como salida:

Cifrado de un archivo con hash_file en PHP - Hielo Creativo

Creación de contraseñas fuertes en PHP

Pese a todo, las funciones anteriores todavía pueden considerarse débiles ya que por lo general producen como resultado un hash de 60 caracteres o menos. Como resultado, un atacante puede tomar poco tiempo en obtener el string real de la contraseña. Por lo tanto, un hash considerado como fuerte debe por ende tener al menos 60 caracteres.

Existen diversos algoritmos para encriptar considerados fuertes, no obstante en PHP los principales son crypt blowfish y argon2.

Generando una contraseña fuerte

La función que nos sirve para encriptar contraseñas fuertes se llama password_hash. La ventaja de está función contra todas las anteriores es que está diseñada para utilizar cualquier algoritmo de cifrado nuevo que se integre a PHP.

La sintaxis de la función es la siguiente:

password_hash(string $password, integer $algo, array $options = ?): string

El significado de los parámetros es como sigue:

  • $password – Es la contraseña que vamos a cifrar
  • $algo – Es el algoritmo a utilizar. Está función soporta los siguientes:
    • PASSWORD_DEFAULT: Es el valor por defecto y se adapta al algoritmo más nuevo que se haya integrado a PHP.
    • PASSWORD_BCRYPT: Utiliza el algoritmo Crypt Blowfish.
  • $options – (Opcional) Es un array de opciones para las contraseñas con blowfish. Aunque en realidad no son muchas opciones, las más interesantes son:
    • salt: Utiliza un cadena para generar el hash (obsoleta desde la versión 7 de PHP)
    • cost: Determina el tiempo utilizado para calcular el hash, a mayor es el número, mayor tiempo.

Observemos algunos ejemplos de su uso:

$otraClave = "Soy0tr4Clav#";
$res = password_hash($otraClave, PASSWORD_DEFAULT);
echo "Password Default: $res <br />";
$res = password_hash($otraClave, PASSWORD_BCRYPT);
echo "Password Blowfish: $res <br />";    
$res = password_hash($otraClave, PASSWORD_BCRYPT,["cost"=>10]);
echo "Blowfish con costo: $res <br />";

Cuyo resultado sería:

Cifrando contraseñas con password_hash en PHP - Hielo Creativo

Verificando nuestro contraseña fuerte

Para verificar un hash contra su cadena de texto original, tenemos la función password_verify, la cual regresa true si son coincidentes o false si no lo son. Su sintaxis es como sigue:

password_verify(string $password, string $hash): bool

Siendo que:

  • $password – El string original para la contraseña
  • $hash – El hash generado a raíz del password

Por ejemplo:

$otraClave = "Soy0tr4Clav#";
$res = password_hash($otraClave, PASSWORD_DEFAULT);
if(password_verify($otraClave, $res))
   echo "Contraseña válida";
else echo "Contraseña inválida";

Dando el siguiente resultado:

Verificando contraseñas cifradas en PHP - Hielo Creativo

Cifrar contraseñas con sal

La función crypt puede generar un hash utilizando el algoritmo Encriptación Standard de Datos (DES) el cual toma un texto de longitud fija y mediante una serie de operaciones sobre otro texto genera el hash. Su longitud es de 64 bits.

La sintaxis básica de esta función es la que sigue:

crypt(string $str, string $salt = ?): string

Siendo sus parámetros:

  • $str – Es la cadena para generar el hash
  • $salt – Es la cadena necesaria para generar el hash. Aunque es opcional, si no se proporciona por lo generar el hash resultante es bastante débil.

Ejemplo 1: Contraseña generada con una sal semi aleatoria.

$nuevaClave = "HolaS0yUn4NuevaClav#"; 
$sal1 = "h0l4$0yun4Sa1Cualqu13r%";
$res = crypt($nuevaClave, $sal1);
echo "Contraseña con sal #1: $res <br />";

Resultado:

Cifrando contraseñas con la función Crypt en PHP - Hielo Creativo

Ejemplo 2: Contraseña generada con una sal aleatoria única.

$nuevaClave = "HolaS0yUn4NuevaClav#";
$sal2 = "O/jw2XygQa2.LrIT7CFCBQowLowDP6Y";
$res = crypt($nuevaClave, $sal2);
echo "Contraseña con sal #2: $res <br />";

Resultado:

Cifrar contraseña con sal aleatoria en PHP - Hielo Creativo

Ejemplo 3: Contraseña generada con una sal de 64 bytes totalmente aleatoria y actualizable por cada refresh de página.

$nuevaClave = "HolaS0yUn4NuevaClav#";
$sal3 = bin2hex(random_bytes(64));
$res = crypt($nuevaClave, $sal3);
echo "Contraseña con sal #3: $res <br />";

Dado que es totalmente aleatoria, el resultado final puede variar:

Cifrar contraseñas  de 64 bytes con sal aleatoria en PHP - Hielo Creativo

Sin embargo, en sistemas que soporten más de un algoritmo de cifrado, es posible cambiar el hash al detectarlo con una serie de constantes para los algoritmos más conocidos como STD (CRYPT_STD_DES), DES extendido (CRYPT_EXT_DES), MD5 (CRYPT_MD5), Blowfish (CRYPT_BLOWFISH), SHA256 (CRYPT_SHA256) o SHA512 (CRYPT_SHA512)

Por ejemplo, podemos crear una contraseña bastante fuerte utilizando SHA512 si este es soportado, de lo contrario podemos crear una sal típica de 64 bytes. La función bin2hex convertirá la salida de la función random_bytes en hexadecimal para una sal más potente.

$nuevaClave = "HolaS0yUn4NuevaClav#";
if(CRYPT_SHA512){
   $microSal = bin2hex(random_bytes(16));
   $salPotente = '$6$' . $microSal;
} else $salPotente = bin2hex(random_bytes(64));
$res = crypt($nuevaClave, $salPotente);
echo "Contraseña con sal potente: $res <br />";

Los caracteres $6$ son obligatorios al principio de un salt para SHA512. El resultado puede ser un hash como el que sigue:

Cifrando contraseñas con SHA512 en PHP - Hielo Creativo

Comentarios, dudas o preguntas

¡Y eso es todo! No olvides dejar tus comentarios, dudas y / o preguntas. Con gusto las respondemos.

Califica este contenido
[Total: 0 Promedio: 0]

Entradas relacionadas

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *