反CSRF实现发布旧令牌

时间:2012-07-08 06:14:56

标签: php http-post csrf

我在登录表单上实施CSRF保护时遇到了一些麻烦。以下是登录的一般流程:

这包含在登录页面的顶部:

// Create CSRF token
$token = $auth->random(64); // 64 psuedorandom characters from /dev/urandom
$_SESSION['token'] = $token;

登录表单:

<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post">
<input type="text" name="username" />
<input type="password" name="password" />
<input type="hidden" name="token" value="<?php echo $token; ?>" />
<input type="submit" name="login" value="Login" />
</form>

最后,当表单在页面下方提交时:

if (isset($_POST['login'])) {

    // Bind input to variables
    $username = isset($_POST['username']) ? $_POST['username'] : '';
    $password = isset($_POST['password']) ? $_POST['password'] : '';
    $posttoken = isset($_POST['token']) ? $_POST['token'] : '';

    // Attempt to login
    $auth->login($username, $password, $posttoken);

}

当$ auth-&gt; login收到输入时,问题就开始了。 $ _SESSION标记等于生成的标记,但$ _POST标记等于上次提交时$ _SESSION标记的标记。

来自$ auth-&gt; login:

的var_dumps示例

首先提交var_dump:

$_SESSION Array
[token] => 00a28586a1a89b30149ef130ca6f3c01a25435ad1b0ad1a19326205c75b80d79

$_POST Array
[username] => 
[password] => 
[token] => 2200bb8663f19d66639a7f4791ddb53c9d510802d0ed76c42ac8b3f6d9e1589a
[login] => Login

第二次提交var_dump:

$_SESSION Array
[token] => e093e312b379d766d46083d616fa8655f1565dc19ed6b1f73108546cb5f43fce

$_POST Array
[username] => 
[password] => 
[token] => 00a28586a1a89b30149ef130ca6f3c01a25435ad1b0ad1a19326205c75b80d79
[login] => Login

第三次提交var_dump:

$_SESSION Array
[token] => 8be7ecbdae6274d1ba5ce9e8ace0af7c76e3e7d181c507d3da9b8c35652865cc

$_POST Array
[username] => 
[password] => 
[token] => e093e312b379d766d46083d616fa8655f1565dc19ed6b1f73108546cb5f43fce
[login] => Login

如果仔细观察,可以看到$ _POST令牌只是向下移动 - 成为上次提交时$ _SESSION的内容。

让我感到困惑,因为$token$_SESSION['token']只在页面顶部设置一次 - 当用户点击提交时,它们不应该有所不同。

总结一下,$ _SESSION包含当前生成的令牌,$ _POST包含先前生成的令牌。

有什么想法吗?谢谢!

1 个答案:

答案 0 :(得分:1)

问题是会话令牌在登录处理代码之前被更改,您需要在登录处理代码之后移动令牌生成位。