Zdá se, že vaše námitka proti tomu, aby relace zůstala otevřená, dokud je otevřený prohlížeč, je otázkou automatických útoků. Obnovení tokenu při každém načtení stránky bohužel pouze odrazuje ty nejamatérnější útočníky.
Za prvé, předpokládám, že mluvíme o útocích konkrétně zaměřených na váš web. (Pokud mluvíme o robotech, kteří se jen potulují a odesílají různé formuláře, nejen že by je to nezastavilo, ale existují mnohem lepší a jednodušší způsoby, jak toho dosáhnout.) Pokud je to tak a já se zaměřuji na své můj robot by udělal toto:
- Načíst stránku formuláře.
- Přečíst token na stránce formuláře.
- Odeslat automatický požadavek s tímto tokenem.
- Přejděte na krok 1.
(Nebo kdybych dostatečně prozkoumal váš systém, uvědomil bych si, že kdybych do každého požadavku zahrnul hlavičku „toto je AJAX“, mohl bych si ponechat jeden token navždy. Nebo bych si uvědomil, že token je moje ID relace a poslat můj vlastní PHPSESSID
cookie.)
Tato metoda změny tokenu při každém načtení stránky by absolutně nezastavila někoho, kdo skutečně chtěl aby na tebe tak strašně zaútočil. Protože token nemá žádný vliv na automatizaci, zaměřte se na jeho účinky na CSRF.
Z pohledu blokování CSRF se zdá, že vytvoření jednoho tokenu a jeho udržování, dokud uživatel nezavře prohlížeč, splňuje všechny cíle. Jednoduché útoky CSRF jsou poraženy a uživatel může otevřít více karet.
TL;DR:Obnovení tokenu jednou při každém požadavku nezvýší zabezpečení. Přejděte na použitelnost a proveďte jeden token na relaci.
Nicméně! Pokud máte velké obavy z duplicitního odeslání formuláře, náhodného nebo jiného, tento problém lze stále snadno vyřešit. Odpověď je jednoduchá:použijte dva tokeny pro dvě různé úlohy.
První token zůstane stejný, dokud relace prohlížeče neskončí. Tento token existuje, aby zabránil útokům CSRF. Jakékoli odeslání od tohoto uživatele s tímto tokenem bude přijato.
Druhý token bude jedinečně vygenerován pro každý načtený formulář a bude uložen v seznamu tokenů otevřeného formuláře v datech relace uživatele. Tento token je jedinečný a po použití je zrušen. Příspěvky od tohoto uživatele s tímto tokenem budou přijaty jednou a pouze jednou.
Tímto způsobem, pokud otevřu kartu do formuláře A a kartu do formuláře B, každý z nich má můj osobní anti-CSRF token (o CSRF postaráno) a můj jednorázový token formuláře (o opětovné odeslání formuláře postaráno). Oba problémy jsou vyřešeny bez jakéhokoli negativního dopadu na uživatelskou zkušenost.
Samozřejmě se můžete rozhodnout, že je to příliš mnoho na implementaci pro tak jednoduchou funkci. Myslím, že každopádně je. Bez ohledu na to existuje solidní řešení, pokud ho chcete.