¿Qué tan específicamente debo implementar la protección CSRF?

1

Hay un montón de artículos que explican qué es CSRF y que debo usar un token de CSRF para evitar CSRF. Algunos de ellos mencionan detalles como el uso de SHA256 sobre MD5. Sin embargo, ninguno de ellos explica cómo implementar la protección CSRF en relación con el flujo de usuarios. Por ejemplo, ¿se supone que debo almacenar el token CSRF en una base de datos o puede ser autónomo? Así es como creo que voy a implementar la protección CSRF, avíseme si hay algún problema:

  1. El usuario llega a la página e inicia sesión. Reciben una cookie solo de http que contiene un JWT.

  2. Genero un valor aleatorio de 128-512 bits (longitud fija, decidiré cuánto tiempo es). Luego, concatino el valor y la ID del usuario y HMAC SHA256 procesan el resultado con una clave privada. Inserto tanto el valor aleatorio como el hash en el HTML.

  3. Cada vez que el usuario realiza una solicitud de API, el valor aleatorio y el hash se agregan como encabezado, variable GET o variable POST (¿no hay una diferencia en el derecho de seguridad?).

  4. El servidor concatina el valor dado con la ID del usuario y lo compara con el hash dado. Si coinciden, entonces la parte CSRF está hecha.

¿Es correcta esta implementación? Algunos motivos de preocupación son que el usuario recibe un nuevo token CSRF cada vez que realiza una carga completa de la página. También pueden tener varios tokens válidos si tienen varias pestañas abiertas. Aunque no creo que esto cause problemas.

Editar: Un día entero de leer sobre CSRF más tarde, me di cuenta de que solo puedo poner el JWT en el encabezado de solicitud de la API y eso es todo.

    
pregunta Leo Jiang 08.03.2016 - 19:22
fuente

1 respuesta

1

Recomiendo crear un sistema en el que se envíe un token anti CSRF desde un campo de entrada oculto y se transmita en el encabezado. Ambos deben verificarse en el lado del servidor.

Aquí hay un ejemplo en PHP:

function generateToken($key) {
  $token = base64_encode(openssl_random_pseudo_bytes(16));
  $_SESSION['csrf_' . $key] = $token;
  return $token;
}


function checkToken($key, $value) {
  if (!isset($_SESSION['csrf_' . $key]))
    return false;
  if (!$value)
    return false;
  if ($_SESSION['csrf_' . $key] !== $value)
    return false;

  unset($_SESSION['csrf_' . $key]);
  return true;
}


  if ($_POST and $_POST['action'] == "something")
  {
    $header_token = apache_request_headers()['X-Anti-Csrf-Token'];
    $post_token = $_POST['token'];
    $post_token = str_replace(" ", "+", $post_token);

    if ($header_token == $post_token)
    {
        if (checkToken('settings', $post_token))
        {   
           // ok; do something

        }
     }
     else
     { 
         // wrong; do something
     }


 }

Enviando el encabezado antes de procesarlo:

   <script>
    $("#some_div").submit(function(event) {
      event.preventDefault();

      var $form = $(this),
        url = $form.attr('action');

      var posting = $.ajax(url, {
        type: 'POST',
        processData: true,
        dataType: "text",
        beforeSend: function (xhr) {
        xhr.setRequestHeader('X-Anti-CSRF-Token', $('#token').val());
    }

Este fragmento de código generará el token y lo colocará en un campo de entrada oculto.

<input id="token" type="hidden" value="<?php echo generateToken('settings'); ?>">
    
respondido por el Jeroen - IT Nerdbox 08.03.2016 - 19:27
fuente

Lea otras preguntas en las etiquetas