Sembra che la tua obiezione a lasciare che la sessione rimanga aperta finché il browser è aperto sia un problema di attacchi automatici. Sfortunatamente, l'aggiornamento del token a ogni caricamento di pagina scoraggia solo gli attaccanti più dilettanti.
Innanzitutto, presumo che stiamo parlando di attacchi mirati specificamente al tuo sito. (Se stiamo parlando dei bot che vagano e inviano vari moduli, non solo questo non li fermerebbe, ma ci sono modi molto migliori e più semplici per farlo.) Se è così, e sto prendendo di mira il mio sito, ecco cosa farebbe il mio bot:
- Carica pagina modulo.
- Leggi il token nella pagina del modulo.
- Invia una richiesta automatizzata con quel token.
- Vai al passaggio 1.
(Oppure, se avessi studiato abbastanza il tuo sistema, mi sarei reso conto che se avessi incluso l'intestazione "questo è AJAX" su ogni richiesta, avrei potuto conservare un token per sempre. Oppure mi sarei reso conto che il token è il mio ID di sessione e inviare il mio PHPSESSID
cookie.)
Questo metodo di modifica del token ad ogni caricamento di pagina non farebbe assolutamente nulla per fermare qualcuno che effettivamente voleva per attaccarti così male. Pertanto, poiché il token non ha alcun effetto sull'automazione, concentrati sui suoi effetti su CSRF.
Dal punto di vista del blocco CSRF, creare un token e mantenerlo fino a quando l'utente non chiude il browser sembra raggiungere tutti gli obiettivi. I semplici attacchi CSRF vengono sconfitti e l'utente può aprire più schede.
TL;DR:l'aggiornamento del token una volta per ogni richiesta non aumenta la sicurezza. Scegli l'usabilità e fai un token per sessione.
Tuttavia! Se sei estremamente preoccupato per invii di moduli duplicati, accidentali o meno, questo problema può comunque essere risolto facilmente. La risposta è semplice:usa due token per due lavori diversi.
Il primo token rimarrà lo stesso fino al termine della sessione del browser. Questo token esiste per prevenire gli attacchi CSRF. Qualsiasi invio da questo utente con questo token sarà accettato.
Il secondo token verrà generato in modo univoco per ogni modulo caricato e verrà archiviato in un elenco nei dati della sessione dell'utente dei token dei moduli aperti. Questo token è unico e viene invalidato una volta utilizzato. Gli invii di questo utente con questo token verranno accettati una sola volta.
In questo modo, se apro una scheda nel modulo A e una scheda nel modulo B, ognuno ha il mio token anti-CSRF personale (con cui si è presi cura di CSRF) e il mio token del modulo una tantum (con il reinvio del modulo a cura). Entrambi i problemi vengono risolti senza alcun effetto negativo sull'esperienza utente.
Naturalmente, potresti decidere che è troppo da implementare per una funzionalità così semplice. Penso che lo sia, comunque. Indipendentemente da ciò, esiste una soluzione solida, se lo desideri.