Om jag förstår detta rätt låter det som att du ställer in token för varje begäran. Min gissning skulle vara att den gamla sidan fortfarande har den gamla token. Jag skulle kontrollera om token är inställd innan jag automatiskt blåser bort den.
if (isset($_SESSION['token'])){
//do nothing
} else{
$_SESSION['token'] = md5(rand());
}
Redigera För att besvara din fråga.
Istället för att bara använda en nyckel av "token", skapa en nyckel för varje webbläsarsession.
$_SESSION[$sessionId] = md5(rand());
Tricket kommer naturligtvis att vara att ta reda på när de händer, för om du inte kan använda sessionen kommer du verkligen inte att veta om begäran kommer från en ny eller gammal flik. Du kan använda frågesträngen för att skicka denna parameter runt. I princip alla förfrågningar måste ha denna parameter annars associerar du inte en session med dem.
t.ex.
http://www.yoursite.com/somepage.php?sessionid=<some generated id>
I slutändan kan användaren apa med detta, men jag är inte säker på att det finns någon väg runt det.
Redigera 2 Ok, här är min tanke för hur du ska göra detta. Säkerhetsexperter där ute, flamma gärna upp mig om jag har fel, som jag sa innan jag är ingen expert, men det ser inte ut som att jag kommer att ta mig ur det här utan att föreslå något;-)
Problemet med CSFR är att någon illvillig användare, Bob, kan skapa ett element på en annan webbplats som får Alices webbläsare att göra en begäran till någon annan webbplats och eftersom Alice tidigare hade loggat in och den informationen lagras antingen som en cookie eller Alice känns igen via session, utför webbplatsen begäran som om Alice hade begärt den. Till exempel, om Alices bank är http://www.mybank.com , då kunde Bob skapa ett foruminlägg som innehåller
<img srg="http://www.mybank.com/transferfunds.php?amount=1000&receiver=Bob" />
Alices bank skulle känna igen hennes webbläsare som gjorde förfrågan och trodde att det var hon. Det finns ett par viktiga saker som måste hända (tillsammans kommer någon av dessa att misslyckas göra att attacken misslyckas) för att göra detta till en genomförbar attack (dessa är nyckeln till att förstå hur man förhindrar det):
- Alice måste ha loggat in på sin banksida så att banken kommer ihåg henne. Detta kan hända antingen i en cookie ("kom ihåg mig") eller via session. Men om hon stänger sin webbläsare (avslutar sessionen) eller rensar sina cookies finns det inget hot eftersom bankens webbplats inte känner igen henne och kommer att avslå begäran.
- Bob måste kunna tillhandahålla alla nödvändiga parametrar till begäran, annars kommer bankens webbplats att neka begäran.
För att ge en uppfattning om "tillstånd" ovanpå ett tillståndslöst protokoll (HTTP), kan du verkligen inte komma runt risken i (1). Såvida du inte får folk att alltid klicka på "logga ut" eller stänga deras fönster etc, finns det inget du kan göra kring att lagra information i webbläsaren eller sessionen. Du kan dock förhindra att (2) blir ett problem. Min lösning på detta (och jag är säker på att det finns massor av andra) är att generera en hash, som du gör och lagra den i session.
Till exempel,
$_SESSION['token'] = md5(rand());
Sedan, vad du gör är att lägga till den token till alla dina interna länkar.
http://www.mysite.com/secure.php?token=giuwnrefviunslfghahgliuwnvwrgbaasd a>
Du ALDRIG lagra denna token i webbläsarens minne:d.v.s. en cookie. När förfrågningar görs, innan du gör något, kontrollerar du 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
}
Nyckeln till detta är att alla länkar på din webbplats kommer att innehålla token. Bob har dock inget sätt att veta vad den här token är eftersom den inte lagras i en cookie i webbläsaren. Om han försöker skapa en länk till en av dina sidor kommer den antingen att innehålla fel nyckel, eller så kommer den inte att innehålla någon nyckel och du kan neka det. (För att vara rättvis finns det en chans att han skulle kunna gissa token korrekt för en specifik användare som råkar se hans kod, men det är troligtvis mer sannolikt att han brinner i lågor.)
Det finns inget behov av att tilldela en timeout till token heller eftersom token kommer att raderas när webbläsaren stängs och måste återskapas när användaren besöker webbplatsen.