【发布时间】:2014-01-02 11:25:12
【问题描述】:
我正在使用 Codeigniter,我想防止可能发生的 CSRF 攻击尝试。为了实现这一点,我为每个要保护的表单添加了一个带有随机标记的隐藏输入标签,同时我将这个标记保存在会话中,以便在开始处理此表单数据时进行比较。
// set a token to prevent CSRF attacks
$csrf_token = md5(uniqid(rand(), true));
$this->session->set_userdata("csrf_token", $csrf_token);
表格将如下所示:
<form action="path/to/handler/page" method="post">
<input type="text" name="title">
<input type="text" name="date">
<textarea name="content"></textarea>
<input type="hidden" name="csrf_token" value="<?php echo $this->session->userdata("csrf_token") ?>">
<input type="submit" name="submit" value="Save">
</form>
在我处理提交数据的页面中,我检查了类似这样的 CSRF 攻击:
// make sure there is no CSRF attack attempt
$csrf_token = $this->session->userdata("csrf_token");
if (empty($csrf_token) || $csrf_token !== $this->input->post("csrf_token")) {
die("Some message here!!");
}
而且效果很好。但是正如您所见,我为每个包含表单的页面生成一个随机令牌,在某些情况下,如果我在浏览器中打开另一个选项卡以执行其他操作,这会导致问题。考虑这种情况:
- 我打开了
add.php页面来添加一个新项目。 - 我填写了所有必需的数据,但我没有提交表格。
- 现在我决定在浏览器的另一个选项卡中打开
edit.php页面来编辑现有项目。 - 然后我又回到了填写好的
add.php页面,尝试提交数据。
此时我会收到一个错误,因为当我打开add.php 页面时已存储在会话中的令牌的值已更改并在我打开edit.php 页面时替换为另一个令牌。那么我该如何解决这个问题呢?当每个用户成功登录时,我是否应该只为他生成一个令牌,然后在他可能处理的所有页面中使用这个令牌?这种方法有什么风险或缺点吗?
【问题讨论】:
-
不要使用
rand()- 出于安全目的,它不够随机。 -
@SilverlightFox 你建议改用什么?
标签: php codeigniter security csrf