一个令牌与多个令牌以防止CSRF攻击 [英] One token vs. multiple tokens to prevent CSRF attacks

查看:165
本文介绍了一个令牌与多个令牌以防止CSRF攻击的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用Codeigniter,我想防止CSRF攻击可能发生的尝试。为了实现这一点,我添加了一个隐藏的输入标签与一个随机标记到我想要保护的每个形式,同时我保持这个标记在会话中进行比较,当开始处理此表单数据。

I'm using Codeigniter and I want to prevent CSRF attacks attempts that may happen. 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);

表单将如下所示:

<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攻击类似这样:

And in the page where I handle submitted data I check CSRF attacks something like this:

  // 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:


  1. 我打开 add.php 页面添加一个新项目。

  2. 我填写了所有必填的资料,但没有提交表单。

  3. 现在我决定开启

  4. 然后我回到了 add.php
  1. I opened add.php page to add a new item.
  2. I filled in all required data, but I didn't submit the form.
  3. Now I decided to open edit.php page in another tab in the browser to edit an existing item.
  4. Then I went back to the add.php page that was filled in and tried to submit the data.

此时,当我打开编辑时,打开 add.php 页面时已经存储在会话中的令牌已更改并替换为另一个令牌。 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. 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?

推荐答案

要解决这个问题,您可以创建一个带有唯一键的令牌字符串并在会话中存储密钥/令牌对(在CodeIgniter中作为userdata)。

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).

考虑到这种情况,您需要执行以下步骤:

Considering this scenario, You'll need these steps:


  1. 创建唯一令牌密钥。

  2. 创建令牌字符串。


  3. 为CSRF密钥和令牌创建2个隐藏的< input> 元素。

  4. 通过检查会话中是否存在密钥/令牌来验证发布的密钥/令牌。

  1. Creating a unique token key.
  2. Creating a token string.
  3. Storing the key/token pair in the session (userdata).
  4. Creating 2 hidden <input> elements for CSRF key and token.
  5. Validating the posted key/token by checking the existence of key/token in the session.



< h3>上班:

Getting to work:

$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);

添加隐藏输入 s:

<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.');
    }
}

这篇关于一个令牌与多个令牌以防止CSRF攻击的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆