为什么codeigniter2不以更安全的方式存储csrf_hash,例如会话?

时间:2012-01-08 20:35:57

标签: php security codeigniter csrf codeigniter-2

为什么生成的CSRF保护令牌不会像建议的here那样通过SESSION保存和使用?目前在CI2中,CSRF保护机制(在安全类中)是这样的:

1.在_csrf_set_hash()函数中为CSRF令牌生成唯一值:

$this->csrf_hash = md5(uniqid(rand(), TRUE));

2.将该标记插入表单隐藏字段(使用form_open helper)

3.用户提交表单,服务器通过POST获取令牌。 CI在Input类中的“_sanitize_globals()”函数中执行令牌验证:

$this->security->csrf_verify();

4.安全类的函数“csrf_verify”只检查POST ['token']设置,POST ['token']等于COOKIE ['token'];

public function csrf_verify(){

// If no POST data exists we will set the CSRF cookie
if (count($_POST) == 0)
{
    return $this->csrf_set_cookie();
}

// Do the tokens exist in both the _POST and _COOKIE arrays?
if ( ! isset($_POST[$this->_csrf_token_name]) OR
         ! isset($_COOKIE[$this->_csrf_cookie_name]))
{
    $this->csrf_show_error();
}

// Do the tokens match?

if ($_POST[$this->_csrf_token_name] != $_COOKIE[$this->_csrf_cookie_name])
{
    $this->csrf_show_error();
}

// We kill this since we're done and we don't want to
// polute the _POST array
unset($_POST[$this->_csrf_token_name]);

// Nothing should last forever
unset($_COOKIE[$this->_csrf_cookie_name]);
$this->_csrf_set_hash();
$this->csrf_set_cookie();

log_message('debug', "CSRF token verified ");

return $this;
}

为什么不在会话中存储令牌?恕我直言,只是检查POST ['token']非空并且等于COOKIE ['token']是不够的,因为两者都可能是由恶意网站发送的。

3 个答案:

答案 0 :(得分:4)

有几个原因。

首先,将令牌存储在cookie中并不是不安全的。 Anti-CSRF不是为了防止内容的自动发布,而是为了防止伪造请求作为经过身份验证的用户(通过iframe或简单链接)。只要令牌本身不可猜测,这就足够了。

第二个是如果它存储在会话中,那么您需要启用会话,这也会导致可用性问题,因为如果您的会话超时并且您打开了一个带有表单的页面,则您无法再提交该表单(即使表单本身不需要登录状态。)

答案 1 :(得分:1)

在CodeIgniter中,他们不会在代码中的任何地方使用本机PHP会话。

您提供的示例使用本机PHP会话显示。

在使用CodeIgniter Session类时,还可以:通过cookie存储数据,或将它们存储在数据库中。 [参考:http://codeigniter.com/user_guide/libraries/sessions.html]

在检查csrf数据时,每次检查数据库都没有意义,将它们存储在cookie中是合理的。

我认为它通常是安全的,但这种方法存在一些漏洞。也许使用服务器端密钥对其进行加密可能有助于提高安全性......

编辑:

https://code.djangoproject.com/wiki/CsrfProtection#Sessionindependentnonce

根据文章,它说CSRF保护与会话独立的nonce(由CodeIgniter使用)具有CSRF + MITM攻击(Man-in-the-Middle)的漏洞:

  

攻击者可以使用Set-Cookie设置CSRF cookie,然后提供   POST表单数据中的匹配标记。由于该网站没有打平   会话cookie到CSRF cookie,它无法确定   CSRF令牌+ cookie是真实的(做其中一个的哈希等)   它们不起作用,因为攻击者可以从中获得一个有效的对   直接站点,并在攻击中使用该对。)

实际上,函数 csrf_verify()仅检查cookie和输入POST是否为 相等,两者都可以通过简单的javascript创建。如果你认真对待安全问题,你应该三思而后行。

来源:How does this Man-In-The-Middle attack work?

答案 2 :(得分:1)

因为CSRF代表“跨站点请求伪造”。这种攻击的一个例子就是你知道有人在http://somedomain.com/wordpress安装了wordpress。你可以让他们点击一个新的链接,这真的会在他们的wordpress控制面板上做些坏事。 CSRF旨在防止这种情况,验证采取行动的用户是否打算采取行动。

即使有人知道如何伪造cookie和隐藏的表单字段来匹配,也无法进行该跨站点,并且无论如何也无法阻止。