什么是 CSRF 代币?它的重要性是什么?它是如何运作的?

发布于 2024-10-20 18:16:34 字数 97 浏览 3 评论 0原文

我正在编写一个应用程序(Django,确实如此),我只想了解“CSRF 令牌”实际上是什么以及它如何保护数据。

如果不使用CSRF token,发布的数据会不安全吗?

I am writing an application (Django, it so happens) and I just want an idea of what actually a "CSRF token" is and how it protects the data.

Is the post data not safe if you do not use CSRF tokens?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

゛时过境迁 2024-10-27 18:16:35

这一切的根源是确保请求来自网站的实际用户。为表单生成 csrf 令牌,并且必须与用户的会话绑定。它用于向服务器发送请求,其中令牌对请求进行验证。这是防止 csrf 的一种方法,另一种方法是检查引荐来源网址标头。

The root of it all is to make sure that the requests are coming from the actual users of the site. A csrf token is generated for the forms and Must be tied to the user's sessions. It is used to send requests to the server, in which the token validates them. This is one way of protecting against csrf, another would be checking the referrer header.

放赐 2024-10-27 18:16:34

简单来说,跨站请求伪造 (CSRF)

  • 假设您当前已登录网上银行 www.mybank.com

  • 假设从 mybank.com 进行转账将导致(概念上)表格

    http://www.mybank.com/transfer?to=&amount=;
    

    (该URL不需要您自己的帐号,因为服务器可以通过您的登录来推断它。)

  • < p>您访问 www.cute-cat-pictures.org,却不知道它是一个恶意网站。

  • 如果该网站的所有者知道上述请求的形式(简单!)并正确猜测您已登录 mybank.com(需要一些运气!),他们可能会包含如下请求在他们的页面上:

    http://www.mybank.com/transfer?to=123456&amount=10000
    

    其中 123456 是他们的开曼群岛帐户号码,10000 是您之前很高兴拥有的金额。

  • 检索了www.cute-cat-pictures.org页面,因此您的浏览器将发出该请求。

  • 您的银行无法识别此请求的来源:您的网络浏览器将随您的 www.mybank.com cookie 一起发送该请求,并且它看起来完全合法。你的钱不见了!

这是没有 CSRF 代币的世界。

现在,使用 CSRF 令牌来实现更好的效果:

  • 使用第三个参数扩展传输请求:

    http://www.mybank.com/transfer?to=123456&amount=10000&token=31415926535897932384626433832795028841971
    
  • 该令牌是一个巨大的、无法猜测的随机数,mybank.com 在向您提供该令牌时会将其包含在他们自己的网页上。每次他们向任何人提供任何页面时,情况都是不同的。

  • 攻击者无法猜测令牌,无法说服您的网络浏览器放弃它(如果浏览器工作正常......),因此攻击者将无法创建有效的请求,因为带有错误令牌(或没有令牌)的请求将被 www.mybank.com 拒绝。

结果:您保留 10000 货币单位。

(您的里程可能会有所不同。)

编辑自值得一读的评论,作者:SOFe

值得注意的是,来自 www.cute-cat-pictures.org 的脚本通常无法访问来自 www.mybank.com 的反 CSRF 令牌code> 因为 HTTP 访问控制。对于某些不合理地为每个网站响应发送标头 Access-Control-Allow-Origin: * 且不知道其用途的人来说,此注释非常重要,只是因为他们无法使用其他网站的 API网站。

Cross-Site Request Forgery (CSRF) in simple words

  • Assume you are currently logged into your online banking at www.mybank.com

  • Assume a money transfer from mybank.com will result in a request of (conceptually) the form

    http://www.mybank.com/transfer?to=<SomeAccountnumber>&amount=<SomeAmount>
    

    (The URL doesn't require your own account number, because the server can deduce it by your login.)

  • You visit www.cute-cat-pictures.org, not knowing that it is a malicious site.

  • If the owner of that site knows the form of the above request (easy!) and correctly guesses you are logged into mybank.com (requires some luck!), they could include a request like this on their page:

    http://www.mybank.com/transfer?to=123456&amount=10000
    

    where 123456 is the number of their Cayman Islands account, and 10000 is an amount that you previously thought you were glad to possess.

  • You retrieved that www.cute-cat-pictures.org page, so your browser will make that request.

  • Your bank cannot recognize the origin of this request: your web browser will send the request along with your www.mybank.com cookie and it will look perfectly legitimate. There goes your money!

This is the world without CSRF tokens.

Now for the better one with CSRF tokens:

  • The transfer request is extended with a third argument:

    http://www.mybank.com/transfer?to=123456&amount=10000&token=31415926535897932384626433832795028841971
    
  • That token is a huge, impossible-to-guess random number that mybank.com will include on their own web page when they serve it to you. It is different each time they serve any page to anybody.

  • The attacker is not able to guess the token, is not able to convince your web browser to surrender it (if the browser works correctly...), and so the attacker will not be able to create a valid request, because requests with the wrong token (or no token) will be refused by www.mybank.com.

Result: You keep your 10000 monetary units.

(Your mileage may vary.)

EDIT from comment worth reading by SOFe:

It would be worthy to note that script from www.cute-cat-pictures.org normally does not have access to your anti-CSRF token from www.mybank.com because of HTTP access control. This note is important for some people who unreasonably send a header Access-Control-Allow-Origin: * for every website response without knowing what it is for, just because they can't use the API from another website.

鲜肉鲜肉永远不皱 2024-10-27 18:16:34

是的,发布数据是安全的。但该数据的来源并非如此。这样,有人可以使用 JS 欺骗用户登录您的网站,同时浏览攻击者的网页。

为了防止这种情况,django 将在 cookie 和表单数据中发送随机密钥。
然后,当用户 POST 时,它会检查两个密钥是否相同。如果用户被欺骗,第 3 方网站无法获取您网站的 cookie,从而导致身份验证错误。

Yes, the post data is safe. But the origin of that data is not. This way somebody can trick user with JS into logging in to your site, while browsing attacker's web page.

In order to prevent that, django will send a random key both in cookie, and form data.
Then, when users POSTs, it will check if two keys are identical. In case where user is tricked, 3rd party website cannot get your site's cookies, thus causing auth error.

梨涡少年 2024-10-27 18:16:34

Cloud Under 博客对 CSRF 令牌有很好的解释.(已存档)

假设您有一个类似简化 Twitter 的网站,托管在 a.com 上。
登录用户可以在表单中输入一些文本(推文)
作为 POST 请求发送到服务器并在访问时发布
提交按钮。在服务器上,用户通过 cookie 来识别
包含他们唯一的会话 ID,以便您的服务器知道谁发帖
推文。

表单可以如此简单:

 
<输入类型=“文本”名称=“推文”> <输入类型=“提交”>

现在想象一下,一个坏人将此表单复制并粘贴到他的恶意软件中
网站,比方说 b.com。该表格仍然有效。只要
当用户登录到您的 Twitter 时(即他们拥有有效的
a.com 的会话 cookie),POST 请求将被发送到
http://a.com/tweet 并在用户单击时照常处理
提交按钮。

到目前为止,只要用户意识到这一点,这并不是一个大问题
表单到底是做什么的,但是如果我们的坏人修改了表单怎么办
像这样:

 <表单操作=“https://example.com/tweet”方法=“POST”>
   
   
  

现在,如果您的一位用户最终访问了坏人的网站并点击了
“点击即可获胜!”按钮,表单提交至
您的网站,用户可以通过会话 ID 正确识别
cookie 和隐藏的推文被发布。

如果我们的坏人更糟糕,他会让无辜的用户提交
一旦他们使用 JavaScript 打开他的网页,甚至可能会出现这种形式
完全隐藏在一个不可见的 iframe 中。这基本上是
跨站请求伪造。

可以轻松地从任何地方提交表单。
一般来说,这是一个常见的特征,但还有更多的情况
只允许从域提交表单很重要
它属于哪里。

如果您的 Web 应用程序无法区分,情况会更糟
在 POST 和 GET 请求之间(例如在 PHP 中使用 $_REQUEST 代替)
$_POST)。不要那样做!可以提交数据更改请求
就像 一样简单,
嵌入恶意网站甚至电子邮件中。

如何确保表单只能从我自己的网站提交?
这就是 CSRF 令牌的用武之地。CSRF 令牌是随机的,
难以猜测的字符串。在包含您想要保护的表单的页面上,
服务器将生成一个随机字符串,即 CSRF 令牌,将其添加到
形成为隐藏字段,并以某种方式记住它,或者通过存储
它在会话中或通过设置包含该值的 cookie。现在的
表单看起来像这样:

 <表单操作=“https://example.com/tweet”方法=“POST”>
      <输入类型=“隐藏”名称=“csrf-token”值=“nc98P987bcpncYhoadjoiydc9ajDlcn”>
      <输入类型=“文本”名称=“推文”>
      <输入类型=“提交”>
     

当用户提交表单时,服务器只需比较
已发布字段 csrf-token 的值(名称不
事)与服务器记住的 CSRF 令牌。如果两个字符串
如果相等,服务器可以继续处理该表单。否则
服务器应立即停止处理该表单并以
错误。

为什么这有效?我们的坏人有几个原因
上面的例子无法获取CSRF token:

将静态源代码从我们的页面复制到其他网站
将是无用的,因为隐藏字段的值随着
每个用户。坏人的网站不知道当前用户的
您的服务器将始终拒绝 POST 请求的 CSRF 令牌。

因为坏人的恶意页面是由您的用户浏览器加载的
来自不同的域(b.com 而不是 a.com),坏人没有
有机会编写 JavaScript,加载内容,从而加载我们的内容
用户当前来自您网站的 CSRF 令牌。那是因为网络
浏览器默认不允许跨域AJAX请求。

坏人也无法访问你的服务器设置的cookie,
因为域不匹配。

我什么时候应该防止跨站点请求伪造?如果可以的话
确保不要混淆 GET、POST 和其他请求方法
如上所述,一个好的开始是通过以下方式保护所有 POST 请求
默认。

您不必保护 PUT 和 DELETE 请求,因为
如上所述,浏览器无法提交标准的 HTML 表单
使用这些方法。

另一方面,JavaScript 确实可以发出其他类型的请求,
例如,使用 jQuery 的 $.ajax() 函数,但请记住,对于 AJAX 请求
要工作,域必须匹配(只要您没有明确
否则配置您的网络服务器)。

这意味着,通常您甚至不必向 AJAX 添加 CSRF 令牌
请求,即使它们是 POST 请求,但您必须做出
确保您仅在以下情况下绕过 Web 应用程序中的 CSRF 检查:
POST请求实际上是一个AJAX请求。你可以这样做
寻找像 X-Requested-With 这样的 AJAX 标头的存在
请求通常包括。您还可以设置另一个自定义标头和
检查它是否存在于服务器端。这是安全的,因为
浏览器不会向常规 HTML 表单提交添加自定义标头
(见上文),所以坏人先生没有机会模拟这种行为
带有表格。

如果您对 AJAX 请求有疑问,因为由于某种原因您
无法检查像 X-Requested-With 这样的标头,只需传递
生成 CSRF 令牌到您的 JavaScript 并将令牌添加到 AJAX
要求。有几种方法可以做到这一点;要么将其添加到
有效负载就像常规 HTML 表单一样,或者添加自定义标头
AJAX 请求。只要您的服务器知道在哪里查找它
传入请求并能够将其与原始值进行比较
从会话或 cookie 中记住,您已排序。

The Cloud Under blog has a good explanation of CSRF tokens. (archived)

Imagine you had a website like a simplified Twitter, hosted on a.com.
Signed in users can enter some text (a tweet) into a form that’s being
sent to the server as a POST request and published when they hit the
submit button. On the server the user is identified by a cookie
containing their unique session ID, so your server knows who posted
the Tweet.

The form could be as simple as that:

 <form action="http://a.com/tweet" method="POST">
   <input type="text" name="tweet">
   <input type="submit">
 </form> 

Now imagine, a bad guy copies and pastes this form to his malicious
website, let’s say b.com. The form would still work. As long
as a user is signed in to your Twitter (i.e. they’ve got a valid
session cookie for a.com), the POST request would be sent to
http://a.com/tweet and processed as usual when the user clicks the
submit button.

So far this is not a big issue as long as the user is made aware about
what the form exactly does, but what if our bad guy tweaks the form
like this:

 <form action="https://example.com/tweet" method="POST">
   <input type="hidden" name="tweet" value="Buy great products at http://b.com/#iambad">
   <input type="submit" value="Click to win!">
 </form> 

Now, if one of your users ends up on the bad guy’s website and hits
the “Click to win!” button, the form is submitted to
your website, the user is correctly identified by the session ID in
the cookie and the hidden Tweet gets published.

If our bad guy was even worse, he would make the innocent user submit
this form as soon they open his web page using JavaScript, maybe even
completely hidden away in an invisible iframe. This basically is
cross-site request forgery.

A form can easily be submitted from everywhere to everywhere.
Generally that’s a common feature, but there are many more cases where
it’s important to only allow a form being submitted from the domain
where it belongs to.

Things are even worse if your web application doesn’t distinguish
between POST and GET requests (e.g. in PHP by using $_REQUEST instead
of $_POST). Don’t do that! Data altering requests could be submitted
as easy as <img src="http://a.com/tweet?tweet=This+is+really+bad">,
embedded in a malicious website or even an email.

How do I make sure a form can only be submitted from my own website?
This is where the CSRF token comes in. A CSRF token is a random,
hard-to-guess string. On a page with a form you want to protect, the
server would generate a random string, the CSRF token, add it to the
form as a hidden field and also remember it somehow, either by storing
it in the session or by setting a cookie containing the value. Now the
form would look like this:

    <form action="https://example.com/tweet" method="POST">
      <input type="hidden" name="csrf-token" value="nc98P987bcpncYhoadjoiydc9ajDlcn">
      <input type="text" name="tweet">
      <input type="submit">
    </form> 

When the user submits the form, the server simply has to compare the
value of the posted field csrf-token (the name doesn’t
matter) with the CSRF token remembered by the server. If both strings
are equal, the server may continue to process the form. Otherwise the
server should immediately stop processing the form and respond with an
error.

Why does this work? There are several reasons why the bad guy from our
example above is unable to obtain the CSRF token:

Copying the static source code from our page to a different website
would be useless, because the value of the hidden field changes with
each user. Without the bad guy’s website knowing the current user’s
CSRF token your server would always reject the POST request.

Because the bad guy’s malicious page is loaded by your user’s browser
from a different domain (b.com instead of a.com), the bad guy has no
chance to code a JavaScript, that loads the content and therefore our
user’s current CSRF token from your website. That is because web
browsers don’t allow cross-domain AJAX requests by default.

The bad guy is also unable to access the cookie set by your server,
because the domains wouldn’t match.

When should I protect against cross-site request forgery? If you can
ensure that you don’t mix up GET, POST and other request methods as
described above, a good start would be to protect all POST requests by
default.

You don’t have to protect PUT and DELETE requests, because as
explained above, a standard HTML form cannot be submitted by a browser
using those methods.

JavaScript on the other hand can indeed make other types of requests,
e.g. using jQuery’s $.ajax() function, but remember, for AJAX requests
to work the domains must match (as long as you don’t explicitly
configure your web server otherwise).

This means, often you do not even have to add a CSRF token to AJAX
requests, even if they are POST requests, but you will have to make
sure that you only bypass the CSRF check in your web application if
the POST request is actually an AJAX request. You can do that by
looking for the presence of a header like X-Requested-With, which AJAX
requests usually include. You could also set another custom header and
check for its presence on the server side. That’s safe, because a
browser would not add custom headers to a regular HTML form submission
(see above), so no chance for Mr Bad Guy to simulate this behaviour
with a form.

If you’re in doubt about AJAX requests, because for some reason you
cannot check for a header like X-Requested-With, simply pass the
generated CSRF token to your JavaScript and add the token to the AJAX
request. There are several ways of doing this; either add it to the
payload just like a regular HTML form would, or add a custom header to
the AJAX request. As long as your server knows where to look for it in
an incoming request and is able to compare it to the original value it
remembers from the session or cookie, you’re sorted.

夏了南城 2024-10-27 18:16:34

该网站在制作表单页面时会生成一个唯一的令牌。需要此令牌才能将数据发布/获取回服务器。

由于令牌是由您的网站生成的,并且仅在生成包含表单的页面时提供,因此其他一些网站无法模仿您的表单 - 他们不会拥有令牌,因此无法发布到您的网站。

The site generates a unique token when it makes the form page. This token is required to post/get data back to the server.

Since the token is generated by your site and provided only when the page with the form is generated, some other site can't mimic your forms -- they won't have the token and therefore can't post to your site.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文