Il semble que votre objection à laisser la session ouverte tant que le navigateur est ouvert est le problème des attaques automatisées. Malheureusement, l'actualisation du jeton à chaque chargement de page ne dissuade que les attaquants les plus amateurs.
Tout d'abord, je suppose que nous parlons d'attaques spécifiquement ciblées sur votre site. (Si nous parlons des robots qui se promènent et soumettent divers formulaires, non seulement cela ne les arrêterait pas, mais il existe des moyens bien meilleurs et plus faciles de le faire.) Si tel est le cas, et que je cible mon site, voici ce que ferait mon bot :
- Charger la page du formulaire.
- Lire le jeton sur la page du formulaire.
- Soumettre une demande automatisée avec ce jeton.
- Passez à l'étape 1.
(Ou, si j'étudiais suffisamment votre système, je me rendrais compte que si j'incluais l'en-tête "c'est AJAX" sur chaque requête, je pourrais garder un jeton pour toujours. Ou je me rendrais compte que le jeton est mon identifiant de session, et envoyer mon propre PHPSESSID
cookie.)
Cette méthode consistant à changer le jeton à chaque chargement de page ne ferait absolument rien pour arrêter quelqu'un qui en fait voulait pour vous attaquer si durement. Par conséquent, puisque le jeton n'a aucun effet sur l'automatisation, concentrez-vous sur ses effets sur CSRF.
Du point de vue du blocage de CSRF, la création d'un jeton et sa conservation jusqu'à ce que l'utilisateur ferme le navigateur semble atteindre tous les objectifs. Les attaques CSRF simples sont vaincues et l'utilisateur peut ouvrir plusieurs onglets.
TL;DR :Actualiser le jeton une fois à chaque requête n'améliore pas la sécurité. Optez pour la convivialité et faites un jeton par session.
Cependant! Si vous êtes extrêmement préoccupé par les soumissions de formulaires en double, accidentelles ou autres, ce problème peut toujours être facilement résolu. La réponse est simple :utilisez deux jetons pour deux tâches différentes.
Le premier jeton restera le même jusqu'à la fin de la session du navigateur. Ce jeton existe pour empêcher les attaques CSRF. Toute soumission de cet utilisateur avec ce jeton sera acceptée.
Le deuxième jeton sera généré de manière unique pour chaque formulaire chargé et sera stocké dans une liste dans les données de session de l'utilisateur des jetons de formulaire ouverts. Ce jeton est unique et est invalidé une fois utilisé. Les soumissions de cet utilisateur avec ce jeton seront acceptées une et une seule fois.
De cette façon, si j'ouvre un onglet vers le formulaire A et un onglet vers le formulaire B, chacun a mon jeton anti-CSRF personnel (CSRF pris en charge) et mon jeton de formulaire unique (resoumission de formulaire prise en charge). Les deux problèmes sont résolus sans aucun effet négatif sur l'expérience utilisateur.
Bien sûr, vous pouvez décider que c'est trop à mettre en œuvre pour une fonctionnalité aussi simple. Je pense que oui, en tout cas. Quoi qu'il en soit, une solution solide existe si vous le souhaitez.