我在登录表单上实施 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->login 收到输入时,问题就开始了。$_SESSION 令牌等于生成的令牌,但 $_POST 令牌等于 $_SESSION 令牌在上次提交期间的值。
来自 $auth->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 包含先前生成的令牌。
有任何想法吗?谢谢!