Encriptación de datos en PHP
Hoy veremos como podemos hacer la encriptación de datos en PHP, pero primero que nada deberíamos darle un vistazo a lo que es encriptar.
Introducción
https://blastcoding.com/encriptacion-de-datos-en-php/#introduccion¿Qué es encriptar? Encriptar es equivalente a cifrar
Es un método que permite aumentar la seguridad de un mensaje o de un archivo mediante la codificación del contenido, de manera que solo pueda leerlo la persona que cuente con la clave de cifrado adecuada para descodificarlo.
wikipedia
Veamos un cifrado tonto, para entender el concepto mejor, por ejemplo el cifrado de Cesar que mueve cada letra un determinado número de espacios, supongamos que tenemos el alfabeto y movemos todas las letras hacia atrás o la izquierda 2 espacios.
En este ejemplo la A pasará a ser Y, B pasara a ser Z, C pasara a ser A y asi sucesivamente.
Cifrados Hoy
https://blastcoding.com/encriptacion-de-datos-en-php/#cifrados_hoyHoy en día tenemos una cantidad de cifrados que puede sernos de ayuda, hay cifrados que son menos seguros y otros que son más seguros.
Tenga en cuenta que cifrar cada dato también toma cierta cantidad espacio.
Espacio ocupado por diferentes algoritmos de cifrado (1000 datos de 100 caracteres)
Algoritmo | Longitud del hash | Tamaño total (sin overhead) |
---|---|---|
MD5 | 16 bytes | 16000 bytes |
SHA-256 | 32 bytes | 32000 bytes |
SHA-1 | 20 bytes | 20000 bytes |
Blowfish | 448 bits (56 bytes) | 56000 bytes |
Blowfish (448 bits): | 56 bytes | 56000 bytes |
Blowfish (128 bits): | 16 bytes | 16000 bytes |
Argon2 | 32-128 bytes (configurable) | 32000-128000 bytes |
Argon2i (128 bits): | 32 bytes | 32000 bytes |
Argon2i (256 bits): | 48 bytes | 48000 bytes |
Argon2id (128 bits): | 40 bytes | 40000 bytes |
Argon2id (256 bits): | 56 bytes | 56000 bytes |
Bcrypt | 60 bytes | 60000 bytes |
No es mucho, pero es algo. Cada 100 000 si una columna usa bcrypt usará 6 mb.
En general, el cifrado puede aumentar el tamaño de la base de datos en un 10% a un 400% o más. Esto puede ser un problema significativo para bases de datos grandes con espacio limitado.
Lo ideal es poner un cifrado fuerte en el password como bcrypt y cifrados más débiles en por ejemplo CI mail y otros datos. Algunos datos muchas veces se pueden llegar a poner si cifrado cuando se trata de datos sensibles aunque no es lo recomendado.
Encriptación del Password en PHP
https://blastcoding.com/encriptacion-de-datos-en-php/#passwordEn PHP tenemos 2 funciones que se encargan tanto del encriptado del password como la verificación del password que el usuario ha ingresado, estas son password_hash
y password_verify
y son las recomendables a usar en PHP, de por sí password_hash
nos permite usar bcrypt que es de seguridad alta.
¿Qué es un hash?
Una función criptográfica hash- usualmente conocida como “hash”- es un algoritmo matemático que transforma cualquier bloque arbitrario de datos en una nueva serie de caracteres con una longitud fija. Independientemente de la longitud de los datos de entrada, el valor hash de salida tendrá siempre la misma longitud.
https://latam.kaspersky.com/blog/que-es-un-hash-y-como-funciona/2806/
Ahora que tenemos más claro que es un hash veamos rápidamente estas 2 funciones password_hash
y password_verify
:
password_hash
https://blastcoding.com/encriptacion-de-datos-en-php/#password_hashcrea un password hash
Description / Descripciónpassword_hash(string $password, string|int|null $algo, array $options = []): string
- 1- La columna que almacena los pasword deberia tener mas de 60 caracteres de longitud lo recomendable es 255
- 2- El password que se le pasa a la funcion se trunca a los 72 caracteres
- 3- La constante
PASSWORD_DEFAULT
esta diseñada para utilizar el algoritmo mas fuerte por tanto este puede cambiar en el futuro - 4- la opcion salt esta discontinuada a partir de PHP7
$password
– password del usuario que se está registrando.
$algo
– es el algoritmo que usaremos. Uno de los algoritmos soportados
Los algoritmos soportados para password_hash
son los siguientes:
PASSWORD_DEFAULT
PASSWORD_BCRYPT
PASSWORD_ARGON2I
PASSWORD_ARGON2ID
$options
– opciones que pose el algoritmo.
Veamos un ejemplo de password_hash
<?php // Configuración de la base de datos $host = 'localhost'; $dbname = 'nombre_base_de_datos'; $username = 'usuario'; $password = 'contraseña'; try { // Conexión a la base de datos utilizando PDO $pdo = new PDO("mysql:host=$host;dbname=$dbname", $username, $password); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Datos del usuario (nombre, email y contraseña) $nombre = 'Juan'; $email = 'juan@example.com'; $contrasena = 'contraseña_segura'; // Hash de la contraseña utilizando password_hash $hashedPassword = password_hash($contrasena, PASSWORD_DEFAULT); // Preparar la consulta SQL para insertar datos en la tabla de usuarios $statement = $pdo->prepare("INSERT INTO usuarios (nombre, email, contrasena) VALUES (:nombre, :email, :contrasena)"); // Vincular parámetros $statement->bindParam(':nombre', $nombre); $statement->bindParam(':email', $email); $statement->bindParam(':contrasena', $hashedPassword); // Ejecutar la consulta $statement->execute(); echo "Usuario registrado correctamente."; } catch(PDOException $e) { // En caso de error, mostrar el mensaje de error echo "Error: " . $e->getMessage(); }
Sé que debería de hacer un formulario y validar los inputs y demás cosas, pero a efectos prácticos este ejemplo debería bastar para entender como usarlo.
¿Si eres más veterano en el tema te preguntarás que pasa con el salt que se usa?
A partir de una de las nuevas versiones de PHP el salt pasa a estar dentro de la misma columna del password y es lo que se recomienda en la página oficial de PHP, de hecho en la versión PHP8 no se tendrá en cuenta el salt que proporciones a la función.
La columna password poseerá lo siguiente
si deseas ahondar en el tema te recomiendo leer esto https://www.php.net/manual/en/faq.passwords.php
[ADS_FD/]password_verify
https://blastcoding.com/encriptacion-de-datos-en-php/#password_verifyla función password_verify
verifica que un password coincida con un hash
Su uso general es verificar si un password ingresado por un usuario o desde el login corresponde con el hash que posee ese usuario.
Description / Descripciónpassword_verify(string $password, string $hash): bool
$password
-password ingresado en un input, generalmente el usuario a loguearse.
$hash
-un hash creado por password hash generalmente obtenido de la base de datos.
// See the password_hash() example to see where this came from. $hash = '$2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a'; if (password_verify('rasmuslerdorf', $hash)) { echo 'Password is valid!'; } else { echo 'Invalid password.'; }
Ahora bien, usted puede preguntarse ¿Cómo obtengo el hash?
El hash es obtenido de la base de datos, en realidad deberías de buscar los datos por el nombre del usuario que siempre deberá ser único o también podría ser por su email que también debe ser único.
Encriptar datos sensibles en PHP
https://blastcoding.com/encriptacion-de-datos-en-php/#datos_senciblesPara asegurar datos sensibles vas a tener que utilizar algoritmos AES(Advanced Encryption Standard) para esto puedes utilizar las funciones openssl_encrypt
y openssl_decrypt
.
No uses hashes para esto.
Veamos todas las funciones que tendrías que usar para encriptar utilizando la extensión OpenSSL, pero primero que nada recuerda que estarás usando OpenSSL y, por tanto, deberás tenerlo instalado primero.
Ten en cuenta habilitar openssl en tu apache des comentando la línea ;extension=openssl.so
en tu php.ini
A continuación veremos las funciones que usaremos para encriptar:
openssl_cipher_iv_length
https://blastcoding.com/encriptacion-de-datos-en-php/#openssl_cipher_iv_lengthDetermina la longitud del vector de inicialización para un algoritmo de encriptación y modo.
Description / Descripciónopenssl_cipher_iv_length(string $cipher_algo): int|false
$cipher_algo
– algoritmo que utilizaremos, un cipher es un algoritmo que se utiliza para la encriptación y des-encriptación de datos.
Retornos
int
– la longitud del cipher
false
– en caso de error
openssl_random_pseudo_bytes
https://blastcoding.com/encriptacion-de-datos-en-php/#openssl_random_pseudo_bytesCrea un string pseudo-random con la cantidad de bytes especificados
Description / Descripciónopenssl_random_pseudo_bytes(int $length, bool &$strong_result = null): string
$length
– la longitud deseada del string
$strong_result
(by reference)
Este parámetro no es un parámetro que usaremos y, por tanto, utilizaremos su valor por defecto null
. Este valor en sí determina si el algoritmo se considera fuerte criptográficamente.
openssl_encrypt
https://blastcoding.com/encriptacion-de-datos-en-php/#openssl_encryptEncripta la data dando como resultado un string
openssl_encrypt( string $data, string $cipher_algo, string $passphrase, int $options = 0, string $iv = "", string &$tag = null, string $aad = "", int $tag_length = 16 ): string|false
Esta función tiene una gran cantidad de parámetros, así que veremos los que son de interés para la demostración de encriptación simple que queremos hacer.
$data
– los datos a ser encriptados
$cipher_algo
– el algoritmo de cipher que estemos usando
$passphrase
– llave de encriptación
$iv
– Initialization Vector (IV),
este parámetro no siempre es necesario cuando se utiliza openssl_encrypt
, pero si será necesario en este caso, ya que estaremos usando CBC
$e_key = "EncryptionKey";//la llave de encripcion que deseas ponerle $data = "Sensitive data";//datos a ser encriptados $method = "aes-256-cbc";//algoritmo y opciones $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($method)); // Encrypt the data $encrypted_data = openssl_encrypt($data, $method, $e_key, 0, $iv); echo $encrypted_data;//si hago un echo
Uos8EIOxD6DuuQXyhxTKoQ==
openssl_decrypt
https://blastcoding.com/encriptacion-de-datos-en-php/#openssl_decryptdesencripta la data
Description / Descripciónopenssl_decrypt( string $data, string $cipher_algo, string $passphrase, int $options = 0, string $iv = "", ?string $tag = null, string $aad = "" ): string|false
$data
– en este caso a $data
se le pasarán los datos encriptados
también utilizaremos: $cipher_algo
, $passphrase
y $iv
Veamos como sería su uso, he hecho que este ejemplo de des-encriptación continúe con lo que vimos en la encriptación y, por tanto, $d_data
tendrá como valor Sensitive data(string)
$d_data = openssl_decrypt($encrypted_data, $method, $e_key, 0, $iv); echo "\n Decrypted data: $d_data";
Decrypted data: Sensitive data
Otras formas de encriptar datos sensibles
https://blastcoding.com/encriptacion-de-datos-en-php/#otras_formas_de_encriptarEstá claro que existen paquetes creados por terceros que nos ofrecen facilidades para la encriptación de datos como puede ser libsodium, Defuse Security’s Secure PHP Encryption Library, Halite, phpseclib, sodium, etc.
Mcrypt -no está en la lista porque se encuentra desaconsejado su uso por los mismos creadores de PHP, ya no tiene mantenimiento.