Blog de programación, errores, soluciones

Chose Language:
Author: Admin/Publisher |finished | checked

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.

El cifrado del cesar original movia las letras 3 espacios a la derecha el cifrado anterior es uno de ejemplo

Cifrados Hoy

https://blastcoding.com/encriptacion-de-datos-en-php/#cifrados_hoy

Hoy 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)

AlgoritmoLongitud del hashTamaño total (sin overhead)
MD516 bytes16000 bytes
SHA-25632 bytes32000 bytes
SHA-120 bytes20000 bytes
Blowfish448 bits (56 bytes)56000 bytes
Blowfish (448 bits):56 bytes56000 bytes
Blowfish (128 bits):16 bytes16000 bytes
Argon232-128 bytes (configurable)32000-128000 bytes
Argon2i (128 bits):32 bytes32000 bytes
Argon2i (256 bits):48 bytes48000 bytes
Argon2id (128 bits):40 bytes40000 bytes
Argon2id (256 bits):56 bytes56000 bytes
Bcrypt60 bytes60000 bytes
el overhead corresponde a un 10% más

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.

Algoritmos como, MD5, SHA1 o SHA256 ya no son recomendados para usar en contraseñas, es por esto que en encriptación de password verá algoritmos distintos a estos.

Encriptación del Password en PHP

https://blastcoding.com/encriptacion-de-datos-en-php/#password

En 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_hash

crea un password hash

Description / Descripción
 password_hash(string $password, string|int|null $algo, array $options = []): string
Cosas importantes que debemos de tener en cuenta al utilizar esta funcion.
  • 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

password_verify

https://blastcoding.com/encriptacion-de-datos-en-php/#password_verify

la 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ón
password_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.

Ejemplo de php.net
// 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_sencibles

Para 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_length

Determina la longitud del vector de inicialización para un algoritmo de encriptación y modo.

Description / Descripción
openssl_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_bytes

Crea un string pseudo-random con la cantidad de bytes especificados

Description / Descripción
openssl_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.

En este parámetro no tienes que pasar un valor true o false, sino que debes de pasar una variable donde se alojara este valor.

openssl_encrypt

https://blastcoding.com/encriptacion-de-datos-en-php/#openssl_encrypt

Encripta la data dando como resultado un string

Description / Descripción
 
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

Ejemplo de encriptación con openssl_encrypt
$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_decrypt

desencripta la data

Description / Descripción
  
 openssl_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_encriptar

Está 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.

Category: php
Something wrong? If you found an error or mistake in the content you can contact me on Twitter | @luisg2249_luis.
Last 4 post in same category