为什么我们需要 csrftoken cookie 和 HTML 表单的隐藏输入的 csrfmiddlewaretoken 值?
我正在努力学习安全知识。我很好奇为什么在 Django 中提交表单(POST)时,有 2 个单独的元素包含相同的 csrf 令牌值:
The
csrftoken
cookie:{' csrftoken':'1effe96056e91a8f58461ad56c0d4ddc',...
表单的隐藏
csrfmiddlewaretoken
:< QueryDict: {u'csrfmiddlewaretoken': [u'1effe96056e91a8f58461ad56c0d4ddc'], ...
如果 Django 将隐藏的 csrf 字段/值插入到 将其发送到浏览器 (GET) 时的表单,并期望 收到POST时返回相同的值,那为什么呢 还需要设置cookie吗?
一个更普遍的问题,如果其中任何一个缺失(表单、cookie),您能否提供一个场景来解释如何利用它(安全攻击)?
顺便说一下,我进行了一些简单的测试以确保 Django 分别检查每一个的有效性 确实是这样:
如果我在执行 POST 之前更改表单的 csrf 值, 我收到此调试错误:
<块引用>CSRF 令牌缺失或不正确
如果我在执行 POST 之前删除 csrf cookie, 我收到了不同的错误:
<块引用>未设置 CSRF cookie。
我只是熟悉基本的 csrf 概念并且想要 了解 django 如何帮助防范此类攻击。
I'm trying to learn about security. I am curious about why, in Django, when submitting a form (a POST), there are 2 separate elements that contain the same csrf token value:
The
csrftoken
cookie:{'csrftoken': '1effe96056e91a8f58461ad56c0d4ddc', ...
The form's hidden
csrfmiddlewaretoken
:<QueryDict: {u'csrfmiddlewaretoken': [u'1effe96056e91a8f58461ad56c0d4ddc'], ...
If Django is inserting the hidden csrf field/value to
the form when it sends it to the browser (GET), and expects the
same value back when receiving the POST, then why is it
necessary to also set a cookie?
A more general question, if either of them was missing (form, cookie), could you provide a scenario that explains how this could be exploited (security attack)?
By the way, I ran a couple of simple tests to make sure that
Django was checking the validity of each one separately and
indeed it is:
If I change the form's csrf value before doing the POST,
I get this debug error back:CSRF token missing or incorrect
If I delete the csrf cookie before doing the POST,
I get a different error back:CSRF cookie not set.
I'm just familiar with basic csrf concepts and want to
learn how django helps protect against these types of attacks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
来自 Jeff Atwood 的博客文章:
防止 CSRF 和 XSRF 攻击
(2008 年 10 月 14 日)
原始帖子
泽勒论文(pdf)推荐“双重提交”
cookie”方法来防止XSRF:
From Jeff Atwood's blog entry:
Preventing CSRF and XSRF Attacks
(Oct 14, 2008)
The original post
The Felten and Zeller paper (pdf) recommends the "double-submitted
cookie" method to prevent XSRF:
该 cookie 是为了支持 AJAX。引用 Django 文档:
The cookie is there for AJAX support. Quoting the Django docs:
他们发现了两个不同的问题。
Cookie 用于验证建立连接的客户端计算机。
隐藏的表单字段用于验证表单的来源。
示例场景:客户端计算机上的用户 A 可以为表单添加书签。用户 B 登录,从今天起获得有效的 cookie。当浏览器具有用户 B 会话中剩余的 cookie 时,用户 A 可以提交昨天的无效表单字段。
无。
CSRF 令牌建立身份。
一台(且仅有一台)浏览器具有 CSRF cookie 令牌。但该浏览器可能会打开一个站点或添加书签的表单的多个副本。
该浏览器上的一个(且仅有一个)页面表单具有 CSRF 表单令牌。
浏览器和表单 cookie 必须匹配,以确保一个浏览器/一个表单。
They spot two different problems.
Cookie is to authenticate the client machine making the connection.
The hidden form field is to authenticate the source of the form.
Example Scenario: User A, on the client machine could bookmark the form. User B logs on, gets a valid cookie from today. User A could submit the invalid form field from yesterday when the browser has a left-over cookie from user B's session.
None.
The CSRF tokens establish identity.
One (and only one) browser has a CSRF cookie token. But that browser could have multiple copies of a site open or bookmarked forms.
One (and only one) page form on that browser has a CSRF form token.
The browser and form cookies must match to assure one browser/one form.
这是一个非常古老的问题,但我认为指出以下几点很重要。
在 Django 5.0.6(可能还有其他早期的 Django 版本)中,csrftoken cookie 和
csrfmiddleware
值(HTML 表单的隐藏输入)不相同。显然,这是为了防止 BREACH 攻击。csrfmiddleware
作为csrftoken
的函数和随机生成的掩码(在get_token
函数中)进行计算,因此csrfmiddleware
code> 对于每个 GET 请求都是不同的,这意味着,每当您使用表单重新加载页面时,您都会得到不同的csrfmiddleware
,但您仍然应该拥有相同的csrftoken
>,尽管csrftoken
也可能过期。您可以打开浏览器的开发者工具自行检查。有关 Django 中 CSRF 保护如何工作的说明,请参阅官方文档,虽然一开始我觉得很混乱,所以你可能想寻找其他更好的解释。 源代码也可以帮助您了解详细信息。
This is a very old question, but I think it's important to point out the following.
In Django 5.0.6 (and possibly other previous Django versions), the
csrftoken
cookie and thecsrfmiddleware
value (of the HTML form's hidden input) are not the same. Apparently, this is to protect against BREACH attacks.The
csrfmiddleware
is computed as a function ofcsrftoken
and a randomly generated mask (in theget_token
function), so thecsrfmiddleware
is different for each GET request, which means that, whenever you reload the page with the form, you will get a differentcsrfmiddleware
, but you should still have the samecsrftoken
, althoughcsrftoken
can also expire. You can open your browser's developer tools and check for yourself.An explanation of how CSRF protection works in Django can be found in the official documentation, although I found it confusing at the beginning, so you may want to look for other better explanations. The source code may also help you understand the details.