2012-07-08 82 views
0

我在登录表单上实施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-> login接收到输入时,问题就会出现。 $ _SESSION标记等于生成的标记,但$ _POST标记等于$ _SESSION标记在上次提交过程中的标记。

来自实例$ auth- 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

好像是这样的问题: '<形式行动= “<?PHP的echo $ _ SERVER [ 'PHP_SELF'];>” 方法= “邮报”>' 当提交页面时,生成一个新的标记并将其添加到'$ _SESSION'中,而旧的标记则在'$ _POST'中传递,导致匹配失败。 我还没有找到解决方法,同时仍然使用每个请求令牌并保持窗体和PHP在同一页面上处理它。 – ssh2ksh 2012-07-08 19:26:42

+0

我收回它!解决方案是将登录处理代码放置在页面的顶部,令牌生成代码在其下方,最后是底部的表单。最初你的解决方案不起作用,因为处理程序仍然在表单之下。公认! – ssh2ksh 2012-07-08 19:38:45

+0

很高兴,我努力回答这个问题,因为我在iPad上。否则会提供更多信息。 – Dale 2012-07-09 16:53:31