Pokud tomu dobře rozumím, zdá se, že token nastavujete pro každý požadavek. Hádám, že stará stránka má stále starý token. Před automatickým odpálením bych zkontroloval, zda je token nastaven.
if (isset($_SESSION['token'])){
//do nothing
} else{
$_SESSION['token'] = md5(rand());
}
Upravit Odpověď na vaši otázku.
Namísto použití jednoho klíče „tokenu“ vytvořte klíč pro každou relaci prohlížeče.
$_SESSION[$sessionId] = md5(rand());
Trik bude samozřejmě v tom, zjistit, kdy k tomu dojde, protože pokud nemůžete použít relaci, opravdu nebudete vědět, zda požadavek přichází z nové karty nebo ze staré. K předání tohoto parametru můžete použít řetězec dotazu. V podstatě všechny požadavky by musely mít tento parametr, jinak s nimi relaci nepřidružíte.
např.
http://www.yoursite.com/somepage.php?sessionid=<some generated id>
Nakonec by se s tím uživatel mohl opičit, ale nejsem si jistý, že to jde nějak obejít.
Úprava 2 Ok, tady je můj nápad, jak byste to měli udělat. Bezpečnostní experti, klidně mě udělejte, pokud se mýlím, jak jsem řekl dříve, nejsem žádný odborník, ale nezdá se, že bych se z toho dostal, aniž bych něco navrhl;-)
Problém s CSFR spočívá v tom, že nějaký uživatel se zlými úmysly, Bob, mohl vytvořit prvek na jiném webu, který způsobí, že prohlížeč Alice odešle požadavek na jiný web, a protože Alice se předtím přihlásila a tyto informace jsou uloženy buď jako cookie nebo Alice je rozpoznán prostřednictvím relace, web provede požadavek, jako by ho Alice požadovala. Pokud je například Aliceova banka http://www.mybank.com , pak by mohl Bob vytvořit příspěvek na fóru, který obsahuje
<img srg="http://www.mybank.com/transferfunds.php?amount=1000&receiver=Bob" />
Alicina banka by poznala, že žádost odeslal její prohlížeč, myslela by si, že je to ona. Aby se z tohoto útoku stal životaschopný útok, musí se stát několik klíčových věcí (společně každá z nich způsobí selhání útoku):
- Alice se musí přihlásit na stránky své banky, aby si ji banka zapamatovala. K tomu může dojít buď v souboru cookie („zapamatovat si mě“) nebo prostřednictvím relace. Pokud však zavře prohlížeč (ukončí relaci) nebo vymaže soubory cookie, nic nehrozí, protože web banky ji nepozná a žádost zamítne.
- Bob musí být schopen dodat žádosti všechny potřebné parametry, jinak webová stránka banky žádost zamítne.
Aby bylo možné poskytnout určitou představu o „stavu“ nad bezstavovým protokolem (HTTP), opravdu nemůžete obejít riziko v (1). Pokud lidi nepřimějete, aby vždy klikli na „odhlásit“ nebo zavřeli okno atd., nemůžete nic dělat s ukládáním informací v prohlížeči nebo relaci. Můžete však zabránit tomu, aby (2) byl problém. Moje řešení (a jsem si jistý, že existuje spousta dalších) je vygenerovat hash, jako to děláte vy, a uložit ho do relace.
Například,
$_SESSION['token'] = md5(rand());
Potom připojíte tento token ke všem svým interním odkazům.
http://www.mysite.com/secure.php?token=giuwnrefviunslfghahgliuwndvwrg a>
Vy NIKDY uložit tento token do paměti prohlížeče:tj. cookie. Když jsou vzneseny požadavky, než cokoli uděláte, zkontrolujete token
//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
}
Klíčem k tomu je, že všechny odkazy na vašem webu budou obsahovat token. Bob však nemá žádný způsob, jak zjistit, co je to token, protože není uložen v cookie v prohlížeči. Pokud se pokusí vytvořit odkaz na jednu z vašich stránek, bude buď obsahovat špatný klíč, nebo nebude obsahovat žádný klíč a můžete jej zamítnout. (Abych byl spravedlivý, existuje šance, že by mohl správně uhodnout token pro konkrétního uživatele, který náhodou viděl jeho kód, ale pravděpodobně bude pravděpodobnější, že vzplane.)
Tokenu není třeba přiřazovat časový limit, protože token bude vymazán po zavření prohlížeče a bude nutné jej znovu vytvořit, když uživatel navštíví web.