Si je comprends bien, il semble que vous définissiez le jeton pour chaque demande. Je suppose que l'ancienne page a toujours l'ancien jeton. Je vérifierais si le jeton est défini avant de le détruire automatiquement.
if (isset($_SESSION['token'])){
//do nothing
} else{
$_SESSION['token'] = md5(rand());
}
Modifier Pour répondre à votre question.
Plutôt que d'utiliser une seule clé de "jeton", créez une clé pour chaque session de navigateur.
$_SESSION[$sessionId] = md5(rand());
L'astuce, bien sûr, consistera à déterminer quand cela se produit, car si vous ne pouvez pas utiliser la session, vous ne saurez vraiment pas si la demande provient d'un nouvel onglet ou d'un ancien. Vous pouvez utiliser la chaîne de requête pour transmettre ce paramètre. Fondamentalement, toutes les demandes devraient avoir ce paramètre, sinon vous ne leur associez pas de session.
ex.
http://www.yoursite.com/somepage.php?sessionid=<some generated id>
En fin de compte, l'utilisateur pourrait jouer avec cela, mais je ne suis pas sûr qu'il y ait un moyen de contourner cela.
Modifier 2 Ok, voici ma pensée sur la façon dont vous devriez faire cela. Experts en sécurité, n'hésitez pas à m'enflammer si j'ai tort, comme je l'ai déjà dit, je ne suis pas un expert, mais il ne semble pas que je vais m'en sortir sans suggérer quelque chose;-)
Le problème avec CSFR est qu'un utilisateur malveillant, Bob, pourrait créer un élément sur un autre site qui amènerait le navigateur d'Alice à faire une demande vers un autre site et, parce qu'Alice s'était déjà connectée et que ces informations sont stockées sous forme de cookie ou Alice est reconnu via session, le site exécute la requête comme si Alice l'avait demandée. Par exemple, si la banque d'Alice est http://www.mybank.com , Bob pourrait alors créer un message de forum contenant
<img srg="http://www.mybank.com/transferfunds.php?amount=1000&receiver=Bob" />
La banque d'Alice reconnaîtrait son navigateur comme faisant la demande, pensant que c'est elle. Il y a quelques éléments clés qui doivent se produire (ensemble, l'échec de l'un ou l'autre de ces éléments entraînera l'échec de l'attaque) pour en faire une attaque viable (ce sont les éléments clés pour comprendre comment l'empêcher) :
- Alice doit s'être connectée au site de sa banque pour que la banque se souvienne d'elle. Cela peut se produire soit dans un cookie ("se souvenir de moi"), soit via une session. Cependant, si elle ferme son navigateur (met fin à la session) ou efface ses cookies, il n'y a aucune menace car le site de la banque ne la reconnaîtra pas et refusera la demande.
- Bob doit être en mesure de fournir tous les paramètres nécessaires à la demande, sinon le site Web de la banque refusera la demande.
Afin de fournir une notion d '"état" en plus d'un protocole sans état (HTTP), vous ne pouvez vraiment pas contourner le risque en (1). À moins que vous n'obligiez les gens à toujours cliquer sur "se déconnecter" ou à fermer leur fenêtre, etc., vous ne pouvez rien faire pour éviter de stocker des informations dans le navigateur ou la session. Cependant, vous pouvez empêcher (2) d'être un problème. Ma solution à cela (et je suis sûr qu'il y en a des tonnes d'autres) est de générer un hachage, comme vous le faites et de le stocker en session.
Par exemple,
$_SESSION['token'] = md5(rand());
Ensuite, vous ajoutez ce jeton à tous vos liens internes.
http://www.mysite.com/secure.php?token=giuwnrefviunslfghahgliuwnvwrgbaasd
Vous JAMAIS stocker ce jeton dans la mémoire du navigateur :c'est-à-dire un cookie. Lorsque des demandes sont faites, avant de faire quoi que ce soit, vous vérifiez le jeton
//note, you'll want to sanitize user input, I'm just being brief
if ($_GET['token'] != $_SESSION['token']){
//User either attempted to enter a link on their own or it's a CSRF attack
header('HTTP/1.1 403 Forbidden');
}else{
//do whatever needs to be done
}
La clé de cela est que tous les liens de votre site incluront le jeton. Cependant, Bob n'a aucun moyen de savoir ce qu'est ce jeton car il n'est pas stocké dans un cookie sur le navigateur. S'il tente de créer un lien vers l'une de vos pages, soit il contiendra la mauvaise clé, soit il ne contiendra aucune clé et vous pourrez le nier. (Pour être juste, il y a une chance qu'il puisse deviner correctement le jeton d'un utilisateur spécifique qui visualise son code, mais il est probablement plus susceptible de s'enflammer.)
Il n'est pas non plus nécessaire d'attribuer un délai d'expiration au jeton, car le jeton sera effacé lorsque le navigateur sera fermé et devra être régénéré lorsque l'utilisateur visitera le site.