Если я правильно понимаю, похоже, что вы устанавливаете токен для каждого запроса.Я думаю, что старая страница все еще имеет старый токен.Я бы проверил, установлен ли токен перед автоматическим удалением.
if (isset($_SESSION['token'])){
//do nothing
} else{
$_SESSION['token'] = md5(rand());
}
Редактировать Чтобы ответить на ваш вопрос.
Вместо того, чтобы просто использовать один ключ"токен", создайте ключ для каждой сессии браузера.
$_SESSION[$sessionId] = md5(rand());
Хитрость, конечно, будет в том, чтобы выяснить, когда это произойдет, потому что, если вы не можете использовать сессию, вы действительно не будете знать, поступает ли запрос с новой вкладки или со старой.Вы можете использовать строку запроса для передачи этого параметра.В основном все запросы должны иметь этот параметр, иначе вы не будете ассоциировать с ними сеанс.
например,
http://www.yoursite.com/somepage.php?sessionid=<some generated id>
В конечном счете, пользователь может с этим справиться, но я не уверен, что есть какой-то способ обойти это.
Редактировать 2 Хорошо, вот моя мысль о том, как вы должны это сделать.Эксперты по безопасности, не стесняйтесь меня обвинять, если я ошибаюсь, как я уже говорил, я не эксперт, но не похоже, что я выйду из этого, не предложив чего-либо; -)
Проблема с CSFR заключается в том, что какой-то злонамеренный пользователь, Боб, может создать элемент на другом сайте, который заставляет браузер Алисы сделать запрос на другой сайт, и потому что Алиса ранее вошла в систему и эта информация сохраняется либо какcookie или Алиса распознаются через сеанс, сайт выполняет запрос, как если бы Алиса запросила его.Например, если банк Алисы - http://www.mybank.com,, тогда Боб может создать сообщение на форуме, содержащее
<img srg="http://www.mybank.com/transferfunds.php?amount=1000&receiver=Bob" />
Банк Алисы распознает ее браузер как запрос, думая, что это она.Есть несколько ключевых вещей, которые должны произойти (вместе, каждое из которых приведет к провалу атаки), чтобы сделать это жизнеспособной атакой (вот ключевые для понимания того, как ее предотвратить):
- Алиса должна зайти на свой банковский сайт, чтобы банк ее запомнил.Это может произойти либо в файле cookie («запомнить меня»), либо в сеансе.Однако если она закроет свой браузер (завершит сеанс) или очистит файлы cookie, угрозы не будет, потому что сайт банка не узнает ее и отклонит запрос.
- Боб должен быть в состоянии предоставить всенеобходимые параметры для запроса, в противном случае веб-сайт банка отклонит запрос.
Чтобы дать некоторое представление о «состоянии» поверх протокола без учета состояния (HTTP), вы действительно не можетеобойти риск в (1).Если вы не заставите людей всегда нажимать кнопку «Выйти» или закрыть окно и т. Д., Вы ничего не сможете сделать, храня информацию в браузере или сеансе.Однако вы можете предотвратить возникновение проблемы (2).Мое решение этого (и я уверен, что есть множество других) состоит в том, чтобы сгенерировать хеш, как вы делаете, и сохранить его в сеансе.
Например,
$_SESSION['token'] = md5(rand());
Затем вы добавляете этот токен ко всем внутренним ссылкам.
http://www.mysite.com/secure.php?token=giuwnrefviunslfghahgliuwnvwrgbaasd
Вы НИКОГДА сохранить этот токен в памяти браузера: то есть, cookie.Когда поступают запросы, прежде чем что-либо делать, вы проверяете токен
//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
}
Ключом к этому является то, что все ссылки на вашем сайте будут включать токен.Однако у Боба нет возможности узнать, что это за токен, потому что он не хранится в cookie в браузере.Если он попытается создать ссылку на одну из ваших страниц, она либо будет содержать неправильный ключ, либо не будет содержать какой-либо ключ, и вы можете отрицать это.(Чтобы быть справедливым, есть шанс, что он мог правильно угадать токен для конкретного пользователя, который случайно просматривает свой код, но он, вероятно, с большей вероятностью загорелся.)
Нет необходимости назначать тайм-аутк токену, так как токен будет уничтожен при закрытии браузера, и его необходимо будет повторно создать, когда пользователь заходит на сайт.