Je lis donc autour et j'étais vraiment confus d'avoir un jeton CSRF, alors que je devrais générer un nouveau jeton pour chaque demande, ou juste par heure ou quelque chose?
$data['token'] = md5(uniqid(Rand(), true));
$_SESSION['token'] = $data['token'];
Mais disons qu'il vaut mieux générer un jeton toutes les heures, alors j'aurais besoin de deux sessions: jeton, expiration,
Et comment vais-je procéder sur le formulaire? Il suffit de mettre echo $ _SESSION ['token'] sur le formulaire de valeur cachée et de comparer ensuite sur submit?
Si vous le faites par demande de formulaire, vous supprimez essentiellement la possibilité que des attaques CSRF se produisent et vous pouvez résoudre un autre problème courant: la soumission de formulaires multiples
En termes simples - votre candidature n'acceptera la saisie du formulaire que si l'utilisateur a DEMANDÉ le formulaire avant la soumission.
Scénario normal: L'utilisateur A se rend sur votre site Web et demande le formulaire A, reçoit le formulaire A plus un code unique pour le formulaire A. Lorsque l'utilisateur soumet le formulaire A, il doit inclure le code unique qui était uniquement pour le formulaire A.
Scénario d'attaque CSRF: L'utilisateur A se rend sur votre site Web et demande le formulaire A. Pendant ce temps, il visite un autre "mauvais" site, qui tente une attaque CSRF contre lui, l'obligeant à se soumettre pour un faux formulaire B .
Mais votre site Web sait que l'utilisateur A n'a jamais demandé le formulaire B - et donc même s'il a le code unique pour le formulaire A, le formulaire B sera rejeté, car il n'a pas de code unique pour le formulaire B, seulement un code pour le formulaire A. Votre utilisateur est en sécurité et vous pouvez dormir tranquille la nuit.
Mais si vous le faites comme un jeton générique, d'une durée d'une heure (comme vous l'avez signalé ci-dessus) - alors l'attaque ci-dessus pourrait fonctionner, auquel cas vous n'avez pas fait grand-chose avec votre protection CSRF. En effet, la demande ne sait pas que le formulaire B n'a jamais été demandé en premier lieu. Il s'agit d'un jeton générique. Le POINT ENTIER de la prévention du CSRF est de rendre chaque jeton de formulaire unique à ce formulaire
Modifier: parce que vous avez demandé plus d'informations: 1 - vous n'avez pas à le faire par demande de formulaire, vous pouvez le faire par heure/session etc. Le point est une valeur secrète qui est donnée à l'utilisateur , et resoumis au retour. Cette valeur n'est pas connue d'un autre site Web et ne peut donc pas soumettre un faux formulaire.
Vous générez donc le jeton par demande ou par session:
// Before rendering the page:
$data['my_token'] = md5(uniqid(Rand(), true));
$_SESSION['my_token'] = $data['my_token'];
// During page rendering:
<input type="hidden" name="my_token" id="my_token" value="<? php echo $_SESSION['my_token']?>" />
// After they click submit, when checking form:
if ($_POST['my_token'] === $_SESSION['my_token'])
{
// was ok
}
else
{
// was bad!!!
}
et parce que c'est "par formulaire" - vous n'obtiendrez pas de soumissions en double - parce que vous pouvez effacer le jeton après la première soumission de formulaire!
Généralement, il suffit d'avoir un seul jeton par utilisateur ou par session. Il est important que le jeton soit lié à un seul utilisateur/session particulier et non utilisé globalement.
Si vous craignez que le jeton ne soit divulgué ou obtenu par un site attaquant (par exemple, par XSS), vous pouvez limiter la validité du jeton à un certain délai, à une certaine forme/URL ou à un certain nombre d'utilisations. .
Mais la limitation de la validité présente l'inconvénient qu'elle peut entraîner des faux positifs et donc des restrictions d'utilisation, e. g. une demande légitime peut utiliser un jeton qui vient d'être invalidé car la demande de jeton est trop longue ou le jeton a déjà été utilisé trop souvent.
Donc, ma recommandation est de n'utiliser qu'un seul jeton par utilisateur/session. Et si vous souhaitez plus de sécurité, utilisez un jeton par formulaire/URL par utilisateur/session afin que si un jeton pour un formulaire/URL est divulgué, les autres soient toujours en sécurité.
La réponse à votre question est: cela dépend.
Et vous n'avez pas besoin d'utiliser la session pour les jetons chronométrés, vous pouvez simplement utiliser l'heure du serveur et une clé secrète sur le serveur.
Mais disons qu'il vaut mieux générer un jeton toutes les heures, alors j'aurais besoin de deux sessions: jeton, expiration,
Non, vous avez besoin d'une routine capable de générer un jeton pour un laps de temps. Disons que vous divisez le temps par 30 minutes. Vous créez un jeton pour les 30 minutes actuelles dans le formulaire.
Lorsque le formulaire est soumis et que vous vérifiez le jeton pour l'instant et par rapport à la période de 30 minutes précédente. Par conséquent, un jeton est valide pendant 30 minutes jusqu'à une heure.
$token = function($tick = 0) use($secret, $hash) {
$segment = ((int) ($_SERVER['REQUEST_TIME'] / 1800)) + $tick;
return $hash($secret . $segment);
};
Vous pouvez utiliser les deux méthodes.
1) Un jeton aléatoire pour chaque demande. Et pour résoudre le problème des jetons non synchronisés, vous pouvez utiliser des événements envoyés par le serveur http://www.w3.org/TR/eventsource/ ou des websockets http: //www.w3 .org/TR/websockets / technologie de communication pour mettre à jour les jetons en temps réel pour chaque page.
2) Vous pouvez utiliser un jeton par session utilisateur (pas besoin de le faire par heure) plus facile à mettre en œuvre. Vous n'aurez pas de problème avec la syncronisation mais si le jeton n'est pas trop fort il peut être deviné. Bien sûr, si le jeton est très aléatoire, il sera très difficile pour une personne mal intentionnée de faire une falsification de demande.
P.S. La première méthode est la plus sécurisée mais elle est plus difficile à mettre en œuvre et utilise plus de ressources.