[英]One token vs. multiple tokens to prevent CSRF attacks
I'm using Codeigniter and I want to prevent CSRF attacks attempts that may happen. 我正在使用Codeigniter,我想防止可能发生的CSRF攻击尝试。 And to achieve this I add a hidden input tag with a random token to each form I want to protect, and in the same time I keep this token in a session to compare against when begin handling this form data.
为了实现这一点,我为每个我想要保护的表单添加了一个带有随机令牌的隐藏输入标记,同时我将这个令牌保存在会话中,以便在开始处理此表单数据时进行比较。
// set a token to prevent CSRF attacks
$csrf_token = md5(uniqid(rand(), true));
$this->session->set_userdata("csrf_token", $csrf_token);
And the form will look like this: 表单将如下所示:
<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>
And in the page where I handle submitted data I check CSRF attacks something like this: 在我处理提交数据的页面中,我检查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!!");
}
And that works pretty good. 这非常有效。 But as you see I generate a random token for each page containing a form and in some cases this causes a problem if for example I opened another tab in the browser to perform some another action.
但正如您所见,我为包含表单的每个页面生成一个随机令牌,在某些情况下,如果我在浏览器中打开另一个选项卡以执行其他操作,则会导致问题。 Consider this scenario:
考虑这种情况:
add.php
page to add a new item. add.php
页面添加一个新项目。 edit.php
page in another tab in the browser to edit an existing item. edit.php
页面来编辑现有项目。 add.php
page that was filled in and tried to submit the data. add.php
页面并尝试提交数据。 At this point I will get an error because value of the token that has been stored in the session when I opened add.php
page has been changed and replaced with another token when I open the edit.php
page. 此时我将收到一个错误,因为我打开
add.php
页面时已存储在会话中的令牌值已更改,并在我打开edit.php
页面时替换为另一个令牌。 So how can I fix this problem? 那么我该如何解决这个问题呢? Should I generate just one token for each user when he successfully login and then use this token in all pages that he may deal with?
我是否应该在成功登录时为每个用户生成一个令牌,然后在他可能处理的所有页面中使用此令牌? Does this approach has any risks or any cons?
这种方法有任何风险或缺点吗?
I scanned your post and don't see a reason why not to use the base codeigniter CSRF protection? 我扫描了你的帖子,没有看到为什么不使用基本codeigniter CSRF保护的原因? It seems you are reinventing the wheel and creating problems that don't exist within its standard implementation.
您似乎正在重新发明轮子并创建标准实现中不存在的问题。
Not to mention you are violating DRY principles by trying to print your tokens to every form. 更不用说你试图将你的代币打印到每种形式都违反了DRY原则。 Any reason why not to keep it simple?
有什么理由不保持简单?
Codeigniter has build in CSRF protection that can be enabled in /application/config/config.php Codeigniter内置了CSRF保护,可以在/application/config/config.php中启用
$config['csrf_protection'] = TRUE;
$config['csrf_token_name'] = 'csrf_token_name';
$config['csrf_cookie_name'] = 'csrf_cookie_name';
$config['csrf_expire'] = 7200;
To solve this problem, you could create a token string with a unique key and store the pairs of keys/tokens in the session (as userdata in CodeIgniter). 要解决此问题,您可以使用唯一键创建一个令牌字符串,并在会话中存储键/令牌对(作为CodeIgniter中的userdata)。
Considering this scenario, You'll need these steps: 考虑到这种情况,您需要以下步骤:
<input>
elements for CSRF key and token. <input>
元素。 $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);
Adding hidden input
s: 添加隐藏
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>
Validating the posted key/token: 验证发布的密钥/令牌:
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.');
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.