Amr*_*Amr 6 php security codeigniter csrf
我正在使用Codeigniter,我想防止可能发生的CSRF攻击尝试.为了实现这一点,我为每个我想要保护的表单添加了一个带有随机令牌的隐藏输入标记,同时我将这个令牌保存在会话中,以便在开始处理此表单数据时进行比较.
// set a token to prevent CSRF attacks
$csrf_token = md5(uniqid(rand(), true));
$this->session->set_userdata("csrf_token", $csrf_token);
Run Code Online (Sandbox Code Playgroud)
表单将如下所示:
<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>
Run Code Online (Sandbox Code Playgroud)
在我处理提交数据的页面中,我检查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!!");
}
Run Code Online (Sandbox Code Playgroud)
这非常有效.但正如您所见,我为包含表单的每个页面生成一个随机令牌,在某些情况下,如果我在浏览器中打开另一个选项卡以执行其他操作,则会导致问题.考虑这种情况:
add.php页面添加一个新项目.edit.php在浏览器的另一个选项卡中打开页面来编辑现有项目.add.php填写的页面并尝试提交数据.此时我将收到一个错误,因为当我打开add.php页面时已经存储在会话中的令牌的值已被更改,并在我打开edit.php页面时被另一个令牌替换.那么我该如何解决这个问题呢?我是否应该在成功登录时为每个用户生成一个令牌,然后在他可能处理的所有页面中使用此令牌?这种方法有任何风险或缺点吗?
为了解决这个问题,您可以创建一个具有唯一密钥的令牌字符串,并将密钥/令牌对存储在会话中(作为 CodeIgniter 中的用户数据)。
考虑到这种情况,您将需要执行以下步骤:
<input>为 CSRF 密钥和令牌创建 2 个隐藏元素。$csrf_key = "TOKEN_" . mt_rand(0, mt_getrandmax());
$csrf_token = hash("sha512", mt_rand(0, mt_getrandmax()));
// Store the key/token pair in session
$this->session->set_userdata($csrf_key, $csrf_token);
Run Code Online (Sandbox Code Playgroud)
添加隐藏的input:
<form action="path/to/handler/page" method="post">
<!-- form input elements -->
<input type="hidden" name="csrf_key" value="<?php echo $csrf_key; ?>">
<input type="hidden" name="csrf_token" value="<?php echo $this->session->userdata($csrf_key); ?>">
</form>
Run Code Online (Sandbox Code Playgroud)
验证发布的密钥/令牌:
if (count($_POST)) {
if (! isset($_POST['csrf_key']) or ! isset($_POST['csrf_token'])) {
die('No CSRF token found, invalid request.');
}
$key = $this->input->post('csrf_key');
$token = $this->input->post('csrf_token');
if ($token !== $this->session->userdata($key)) {
die('Invalid CSRF token, access denied.');
}
}
Run Code Online (Sandbox Code Playgroud)