是否可以将CSRF和Nonce令牌结合起来?

时间:2012-10-24 15:04:35

标签: php csrf nonce

首先是一些背景 我一直在使用nonce令牌以相同的方式签署我的表单数据wordpress允许将操作附加到nonce:

// editing post id:10
$post_id = 10;
$nonce = create_nonce( 'edit-post-'.$post_id );
echo '<input type="hidden" name="post_id" value="'.$post_id.'">';
echo '<input type="hidden" name="nonce" value="'.$nonce.'">';

这允许我稍后检查用户是否正在编辑我授予他权限的帖子,因为我重建了nonce并检查我收到的nonce是否与我构造的相同:

$server_nonce = create_nonce( 'edit-post-'.$_POST['post_id'] );
if( $server_nonce != $_POST['nonce'] )
{
    echo 'bad guy...';
}

到目前为止,我误解了这种方法是一种反CSRF令牌,它给了我CSRF保护 当我深入研究CSRF问题时,我发现这个解决方案并不能保护我100%免受CSRF的影响,因为:

  1. 可以使用收到的数据在服务器中重建随机数。 CSRF必须不被重建。
  2. 对于窗口时间的表单,nonce令牌将是相同的。 CSRF必须在每次请求时都是唯一的。
  3. 所以,这是我的问题:

    是否可以在表单中使用两个令牌来保护CSRF和数据签名?有没有办法将这两个令牌结合起来?

1 个答案:

答案 0 :(得分:1)

通常,nonce需要保存在服务器端的某个地方。如果在验证nonce时重新生成nonce,则表示nonce是基于输入的可预测值。这是非常无用的,因为这是一个静态值。它不是 nonce

nonce应该起作用的方式是:

  1. 构建表单
  2. 生成 随机 值,即nonce
  3. 将nonce保存在会话中,将其置于隐藏字段中
  4. 提交表单后,检查提交的nonce是否与会话中的nonce相对应
  5. 其他任何东西只是动作+ post-id的校验和,这是无用的。

    您可以通过获取所有预期字段和其他预期静态值的名称并将其哈希值添加到会话中,轻松地使用要提交字段的校验和来扩展此正确的现时过程。 E.g:

    sha1(join(',', array('first_name', 'last_name', $nonce)))
    

    在表单提交后,获取所有收到的字段名称并再次生成相同的哈希,并检查它是否与会话中的哈希相同。如果没有,有人篡改了表格。