为啥codeigniter2不以更安全的方式存储csrf_hash,比如session?

Posted

技术标签:

【中文标题】为啥codeigniter2不以更安全的方式存储csrf_hash,比如session?【英文标题】:Why codeigniter2 doesn't store the csrf_hash in a more secure way, such as session?为什么codeigniter2不以更安全的方式存储csrf_hash,比如session? 【发布时间】:2012-02-05 13:16:49 【问题描述】:

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

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

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

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

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

$this->security->csrf_verify();

4.Security类的函数“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'] 是不够的,因为两者都可能是由邪恶网站发送的。

【问题讨论】:

我不认为邪恶的网站可以为“好”网站设置 cookie 值:既不能读取也不能写入其他域的 cookie。还是我错过了什么? 也许你是对的,也许这只是使用 SESSION 的另一种方法。只是好奇它是否同样安全。 我对我的问题进行了修改,请查看。谢谢! 【参考方案1】:

有几个原因。

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

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

【讨论】:

我不太同意,它正在检查 cookie 和输入帖子,这样做是非常多余的,因为两者都可以通过某种方式进行更改。基本上,只需设置 cookie 并输入相同的内容,只需一点点 javascript 即可轻松完成。我相信这是 CodeIgniter 中的一个安全漏洞。来源:***.com/questions/6066462/… Matthew:请看我下面的评论。很有趣的是,使用这种方法是否足够。 这可能超出了我的理解范围,但是如果 cookie 设置为仅安全,那么它应该不会受到这种特定类型的攻击。 【参考方案2】:

在 CodeIgniter 中,它们不会在代码中的任何地方使用原生 php 会话。

您提供的示例使用原生 PHP 会话显示。

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

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

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

编辑:

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

根据文章,它说 CSRF Protection with Session Independent 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?

【讨论】:

其实,我的想法和你一样 :) 问题是,一个邪恶的网站 (www.badsite.com) 可以为好网站 (www.goodsite.com) 设置一个 cookie,所以cookie 中的令牌将与邪恶站点发送的 POST 中的令牌匹配,因此好的站点将接收到由邪恶站点设置的 POST 和 cookie?不知何故,从答案中,我认为您可以将 cookie 设置为其他域(来自 evilsite)并期望它会被浏览器自动发送到好的站点。 甚至是的,如果一个邪恶的网站有一些 javascript 代码,受害者从一个邪恶的网站下载,那么 javascript 代码恕我直言可能会改变相关的 cookie:***.com/questions/402348/… 正确,没有第三方网站可以手动修改cookies,但是cookies可以通过恶意javascript修改。【参考方案3】:

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

即使有人知道如何伪造 cookie 和隐藏表单字段以进行匹配,也无法进行跨站点,也无法防止伪造。

【讨论】:

请看下面的@tpae 答案和cmets。 你想让我看什么? CSRF 不是身份验证的替代品,但它——与良好的身份验证相结合——可以防止已经通过身份验证的用户的意外行为......

以上是关于为啥codeigniter2不以更安全的方式存储csrf_hash,比如session?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Typescript 不以正确的方式支持函数重载?

为啥不以编程方式快速更改 uibutton 标题?

为啥 CheckBox 检查不以编程方式与 Kotlin 一起工作?

为啥标准库不以无锁方式为 8 字节以下的结构实现 std::atomic?

为啥 Vector<String> 在以多线程样式访问它时不以同步方式运行 [重复]

为啥 Vector<String> 在以多线程样式访问它时不以同步方式运行 [重复]