简体   繁体   中英

Protect against CSRF attack in PHP for multiple browser tabs

I know, there are two main solutions against CSRF attacks.

  • one token per session
  • tokens for all unique forms

I chose the second one, but there is a problem. If the visitor opens a form in two tabs, then the forms token on the second tab overwrites the previous tokens. I wrote a code for solve this problem. My question is: is it a good solution, or I have to work on it? (There are just the most important parts in the examples.)

##### CONFIG & FUNCTION.PHP #####
// INITIALIZING - RUN ONLY ONCE
$_SESSION["csrf_tokens"]["postcomment"]     = array ();
$_SESSION["csrf_tokens"]["postcommentedit"] = array ();
// etc, etc.
function makearandomtoken ()
{
   // a simple but secure way
   return bin2hex (openssl_random_pseudo_bytes (32));
}

##### POSTCOMMENT_FORM.PHP #####
// new form for comment under a post, so create a new token
$created_token = makearandomtoken ();
array_push ( $_SESSION["csrf_tokens"]["postcomment"], $created_token );
// the form (only with important parts)
print "<form>\n";
print "<input type=\"hidden\" name=\"token\" value=\"$created_token\">\n";
print "</form>\n";

##### POSTCOMMENT_EXECUTE.PHP #####
// get the token from POST variable
$received_token = filter_input (INPUT_POST, 'token', FILTER_UNSAFE_RAW);
// check it
if ( in_array($received_token, $_SESSION["csrf_tokens"]["postcomment"]) )
{
   // VALID token, disable it
   $token_index = array_search($received_token, $_SESSION["csrf_tokens"]["postcomment"]);
   unset ($_SESSION["csrf_tokens"]["postcomment"][$token_index]);
}
else
{
   // INVALID token -> CSRF attempt
   die (); // or do anything
}

I don't see a problem with your implementation, if you want a new token per form instance. Both tabs were legitimately opened by the user, so it makes sense that both tokens would be accepted.

As for the CSRF protection, I think it is intact. A 3rd site could not impersonate the user without have a token, and the user having two or three valid tokens doesn't make the task easier for the attacker.

If you code the front-end, you could register an event handler to the document onUnload event and have the handler make a POST request that tells the server which token is being unloaded. This way the backend could delete the token from the session. That may be more trouble than it's worth though because if the user hits the browser BACK button, she will reload an invalid token and will be frustrated by the error when she submits the form.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM