In quale modo specifico dovrei implementare la protezione CSRF?

1

Ci sono un sacco di articoli che spiegano cos'è CSRF e che dovrei usare un token CSRF per prevenire CSRF. Alcuni di loro menzionano dettagli come l'utilizzo di SHA256 su MD5. Tuttavia, nessuno di essi spiega come implementare la protezione CSRF in relazione al flusso dell'utente. Ad esempio, suppongo di memorizzare il token CSRF in un database o può essere autonomo? Ecco come penso che implementerò la protezione CSRF, fammi sapere se c'è qualcosa di sbagliato:

  1. L'utente arriva alla pagina e accede. Ricevono un cookie http-only contenente un JWT.

  2. Genero un valore casuale di 128-512 bit (lunghezza fissa, deciderò quanto è lungo). Quindi, concatro il valore e l'ID utente e HMAC SHA256 cancellano il risultato con una chiave privata. Inserisco sia il valore casuale che l'hash nel codice HTML.

  3. Ogni volta che l'utente effettua una richiesta API, il valore casuale e l'hash vengono aggiunti come un'intestazione, una variabile GET o una variabile POST (non c'è differenza per la sicurezza vero?).

  4. Il server concatena il valore dato con l'ID dell'utente e lo confronta con l'hash specificato. Se corrispondono, la parte CSRF è terminata.

Questa implementazione è corretta? Alcuni motivi di preoccupazione sono che l'utente riceve un nuovo token CSRF ogni volta che esegue il caricamento di una pagina intera. Possono anche avere più token validi se hanno più schede aperte. Non penso che questi causeranno problemi però.

Modifica Un giorno intero di lettura di CSRF in seguito, mi sono reso conto che posso semplicemente inserire il JWT nell'intestazione della richiesta API e basta.

    
posta Leo Jiang 08.03.2016 - 19:22
fonte

1 risposta

1

Suggerirei di creare un sistema in cui un token anti-CSRF viene inviato da un campo di input nascosto e viene trasmesso nell'intestazione. Entrambi dovrebbero essere controllati sul lato server.

Ecco un esempio in 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
     }


 }

Invio dell'intestazione prima dell'elaborazione:

   <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());
    }

Questo pezzo di codice genererà il token e lo inserirà in un campo di input nascosto.

<input id="token" type="hidden" value="<?php echo generateToken('settings'); ?>">
    
risposta data 08.03.2016 - 19:27
fonte

Leggi altre domande sui tag