[Problema]: Sistema anti ataques (CSRF)

Iniciado por Leguim, 15 Octubre 2019, 00:29 AM

0 Miembros y 1 Visitante están viendo este tema.

Leguim

Buenas noches,
estaba haciendo el siguiente sistema que la idea sería evitar los ataques CSRF en mi aplicación web...

Código (php) [Seleccionar]

$Token_CSRF = Create_Code();
// La función "Create_Code()" lo que hace es crear un token de 22 caracteres entre ellas números y letras


Luego en el formulario tengo un input de tipo hidden

Código (php) [Seleccionar]

<input type="hidden" name="token_csrf" value="<?php echo($Token_CSRF); ?>">


Luego al enviar el formulario lo que hago es comparar si $_POST['token_csrf'] es igual a $Token_CSRF

Código (php) [Seleccionar]

if($_POST['token_csrf'] == $Token_CSRF)
{
     echo "Función ejecutada correctamente";
}
else
{
      echo "Un posible ataque CSRF fue detectado, vuelva a intentarlo.";
}


El problema es que el valor $Token_CSRF y el $_POST nunca van a ser iguales ya que al enviar el formulario no entiendo por qué razón se cambia o se "recrea" el valor de la variable $Token_CSRF ¿Como podría hacer algo para solucionar esto?

MinusFour

Tienes que guardar el token del lado del servidor, lo puedes poner en una sesión por ejemplo. Ese es el valor que tienes que comparar contra el valor que recibes por POST.

Leguim

Cita de: MinusFour en 15 Octubre 2019, 01:22 AM
Tienes que guardar el token del lado del servidor, lo puedes poner en una sesión por ejemplo. Ese es el valor que tienes que comparar contra el valor que recibes por POST.

Si si, estoy guardando el token del lado del servidor pero no entiendo por qué sucede eso... si hasta donde yo lo veo como yo hice debería de funcionar de 100 pero siempre puede pasar que algo se me escape...

Intente con las $_SESSION pero es lo mismo, al enviar dicho formulario como que la variable que guarda el dato de la función "Create_Code" es como que se dispara otra vez, y de esta forma genera un nuevo token sin que yo se lo pida..

@XSStringManolo

Pasa el código que tengas, igual estás metiendo la llamada a la función en un if en vez de la varible que contiene el valor de retorno? Si utilizas la llamada como si fuese el valor del return en el if pasaría eso de que se te ejecuta 2 veces.

#!drvy

#4
Igual estás ejecutando la función antes de la comprobación del token ende se genera un nuevo token antes de validar el antiguo. Si es el caso, yo  lo que suelo hacer es guardar el valor antiguo y el nuevo. Usas el antiguo para comparar y el nuevo para insertar en campos.

Un ejemplo así sin pensarlo mucho:

Código (php) [Seleccionar]
function createToken($name = 'token')
{
   $new_name = 'csrf_'.$name;
   $old_name = 'csrf_old_'.$name;

   if (!empty($_SESSION[$new_name])) {
       $_SESSION[$old_name] = $_SESSION[$new_name];
   }

   $rand = bin2hex(random_bytes(32));
   $_SESSION[$new_name] = $rand;
   return $rand;
}


function validateToken($name = 'token', $value = null)
{
   $old_name = 'csrf_old_'.$name;

   if (!empty($_SESSION[$old_name]) && $_SESSION[$old_name] === $value) {
       return true;
   }

   return false;
}



Código (php) [Seleccionar]
<?php
$csrf_token 
createToken('patata');


if (isset(
$_POST['csrf_token']) && validateToken('patata'$_POST['csrf_token'])) {
    echo 
'token valido';
}

?>



<form method='POST'>
   <input name='csrf_token' type='hidden' value='<?=$csrf_token?>'>
   <button type='submit'>Enviar</button>
</form>




PD: Comprueba siempre los strings con === (3 iguales) en vez de 2.
https://stackoverflow.com/questions/4732706/whats-the-difference-between-equal-and-identical-comparison-operators-in-php

PD2: echo NO es una función. No uses paréntesis () si no vas a hacer comprobaciones.
https://www.php.net/manual/es/function.echo.php
Nota: Puesto que esto es una construcción del lenguaje y no una función, no puede ser llamada usando funciones variables.


Saludos

Leguim

Me dio unos problemas al principio pero ya todo funciona muy bien, me gusto mucho la lógica de tu idea!

Gracias!