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