Validacion de token de forma Criptografica, evitar ataques CSRF

Como implementar una validacion Criptografica de un token previamente cifrado

Publicado por AlbertoBSD el 2019-12-13 04:04:00

Bueno esto viene del tema que abrio el usuario MiguelCanellas [Aporte]: Sistema Anti ataques CSRF (Espero sugerencias).

La forma mas sencilla de genera un token sin incluir nada de criptografia y que se envie al usuario para posteriormente ser validado es la siguiente:

$token = hash("sha256",openssl_random_pseudo_bytes(32));

Esto nos produce una cadena hash sha256 de 1Kilobyte random.

La cosa seria sencilla guardarlo en la $_SESSION en el server y mandarlo al usuario, si lo devuelve comparamos que sean iguales y listo no hay mucho pierde.

Se necesita mas seguridad.... ?

El simple hecho que tengamos un hash sha256 de unk kilobyte random de informacion hace casi imposible que alguien pueda generar el token por si solo y que coincida con el que generamos nosotros, podriamos incrementar la cantidad de bytes generados por la funcion openssl_random_pseudo_bytes simplemente incrementando su valor.

Ahora si realmente queremos proteger la informacion mediante criptografia tenemos que hacer las cosas bien.

Una implentacion rapida para ejemplificar este proceso es la siguiente:


	$cipher = 'AES-256-CBC';									//SUIT de cirado utilizada 
	$strkey = "s3cr3tk3yh4x0r";									//Clave en el servidor, secreta, cambiar esta clave de ejemplo POR FAVOR de preferencia utilizar una clave generada de forma segura con openssl_random_pseudo_bytes o /dev/random
	$realkey = hash("sha256",$strkey,true);						//Hash de la clave en formato Raw
	$ivlen = openssl_cipher_iv_length($cipher);					// Obtenemos el tamaño del Vector Inicializado de acuardo a la Suit de cifrado que estemos utilizando
	$iv = openssl_random_pseudo_bytes($ivlen);					// Obtenemos $ivlen bytes random no nos interesa saber su valor
	$token = hash("sha256",openssl_random_pseudo_bytes(32));	//Token sin cifrar este valor nuca lo ve el UserAgent
	$token_cifrado = openssl_encrypt($token,$cipher,$realkey,OPENSSL_RAW_DATA,$iv); 
	$salida = base64_encode($token_cifrado);					//Este valor si lo ve el User Agent
	echo "token: ".$token."\n";
	echo "token cifrado, salida raw: ".$token_cifrado ."\n";
	echo "token cifrado, salida base64: ".$salida."\n";
	$entrada = base64_decode($salida);
	$token_decifrado = openssl_decrypt($entrada,$cipher,$realkey,OPENSSL_RAW_DATA,$iv);
	echo "token decifrado: ".$token_decifrado ."\n";
	if($token_decifrado == $token)	{
		echo "token correcto\n";
	}
	else	{
		echo "token Incorrecto\n";
	}

Si vemos el codigo anterior el "token" que enviaremos al usuario es la salida en base64 del token previamente cifrado.

Acontinuacion una posible salida de las casi infinitas salidas....


token: 5ab8aac170554a2683e0cc0534a34e80d0f16031a13faa3c3a5ee44902b2c6a1
token cifrado, salida raw: CU?!,F8C4d1su
        SN{|큮vDjUa=qQKKKȀE#(@/I
token cifrado, salida base64: AUO6plUB9j8h+IvsyixGOAfZQzRkCzG84XN1vN7X2Aq2CVNOont87YGudsJEq2q1VWE9vZhxqJWfUUviv0tL9ciA+kWTI74oGEAvl4sSSak=
token decifrado: 5ab8aac170554a2683e0cc0534a34e80d0f16031a13faa3c3a5ee44902b2c6a1
token correcto

La idea en este caso es enviar la informacion cifrada al usurio y cuando este la envie devuelta se descifra y se compara con la almacenada previamente en la $_SESSION del usuario. Cosas que se pueden mejorar el valor de nuestra Key inicial podria ser un archivo random en nuestro servidor generado previamente, podriamos tener una llave distinta por usuario, etc etc etc...

please login
Login to comment
Loging with github