Если я хочу защитить свой сайт и пользователей от атак Cross Site Forgery (CSRF), я могу сгенерировать уникальный токен $token = md5( time() * rand );
на каждой странице, которая имеет форму. Токен отправляется в скрытое поле ввода echo '<input type="hidden" name="token" value="'.$token.'">';
и в то же время хранится в переменной сеанса $_SESSION['token'] = $token;
,
Я проверю, если в любой представленной форме, if($_POST['token'] == $_SESSION['token'])
и действуйте соответственно.
Однако некоторые пользователи могут выполнять многозадачность. Это то, что я сейчас делаю сейчас, пока я публикую это.
Составляя свой пост, я открываю разные окна / вкладки, чтобы, возможно, изучать информацию или просматривать другие вопросы о переполнении стека. Переполнение стека позволяет мне отправить форму без проблем.
Но если бы я сделал это на своем сайте, это означало просмотр других страниц при составлении сообщения / формы – мой $token
был бы регенерирован каждый раз, когда я вытаскиваю другую страницу с моего сайта. Создание скрытого input
токена в форме, над которой я работаю, и в конечном итоге вы хотите отправить неверную информацию , потому что она больше не будет соответствовать переменной $_SESSION['token']
, которая была обновлена, когда я посетил другую страницу …
Любые хорошие идеи, как предотвратить эту проблему, или какие-либо лучшие решения, чтобы остановить CSRF в первую очередь?
Я хочу разрешить моим пользователям многозадачность и хочу, чтобы их защищали от CSRF …
У меня была та же проблема с тем, что вы заявляете из-за одиночного CSRF, и его заменяют, если они не отправляют последнюю страницу, но если вы используете массив w / session, он должен решить вашу проблему. Также вы можете включить капчу, я бы рекомендовал Recaptcha от Google.
session_start(); function createToken(){ $token = sha1(uniqid(mt_rand(), true)); $_SESSION['Tokens']['Token'][] = $token; $_SESSION['Tokens']['Time'][] = time() + (10 * 60); #10 min limit #you can omit/change this if you want to not limit or extend time limit return $token; } function checkToken($token){ clearTokens(); foreach($_SESSION['Tokens']['Token'] as $key => $value){ if($value === $token){ return true; } } return false; } function clearTokens(){ foreach($_SESSION['Tokens']['Time'] as $key => $value){ if($value <= time()){ unset($_SESSION['Tokens']['Token'][$key], $_SESSION['Tokens']['Time'][$key]); #remove last parameter if you aren't using token time limit } } }
ваш HTML:
<input type="hidden" name="token" value="<?php createToken(); ?>">
PHP Token Checker
if(isset($_POST['token']) && checkToken($_POST['token'])){ #valid token }else{ #create error message saying that they tried to repost data or session token expired }
Браузер должен поддерживать правильный идентификатор сеанса даже между вкладками и окнами, идентификатор сеанса должен быть одинаковым. (опасное предположение должно быть проверено на кросс-браузер, чтобы быть уверенным)
генерировать больше токенов, которые должны быть действительными на основе идентификатора сеанса.
так что вы можете проверить что-то вроде этого.
$tokenCorrect = false; foreach($_SESSION['tokens'] as $token) { if ($token !== $_POST['token']) continue; $tokenCorrect = true; } if ($tokenCorrect == false) { die(); // // Maybe log to database ?? but watch if possible Denial of Service because somebody can write your disk/ shared diskspace full with only making fast requests with a invalid CSRF token }