了解 Rails 真实性令牌
Rails 中的真实性令牌是什么?
What is the Authenticity Token in Rails?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
Rails 中的真实性令牌是什么?
What is the Authenticity Token in Rails?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(11)
会发生什么
当用户查看表单来创建、更新或销毁资源时,Rails 应用程序会创建一个随机
authenticity_token
,将此令牌存储在会话中,并将其放置在在表单的隐藏字段中。 当用户提交表单时,Rails 会查找authenticity_token
,将其与存储在会话中的令牌进行比较,如果匹配,则允许请求继续。为什么会发生
由于真实性令牌存储在会话中,客户端无法知道它的值。 这可以防止人们在不查看应用程序本身内的表单的情况下向 Rails 应用程序提交表单。
想象一下,您正在使用服务 A,您登录了该服务,一切正常。 现在想象一下,您去使用服务 B,并且看到了一张您喜欢的图片,并按下该图片以查看更大尺寸的图片。 现在,如果服务 B 存在一些恶意代码,它可能会向服务 A(您已登录)发送请求,并通过向
http://serviceA.example 发送请求来要求删除您的帐户/关闭帐户
。 这就是所谓的 CSRF(跨站请求伪造)。如果服务 A 使用真实性令牌,则此攻击向量不再适用,因为来自服务 B 的请求将不包含正确的真实性令牌,并且将不允许继续。
API 文档 描述了有关元标记的详细信息:
注释
请记住,Rails 只验证非幂等方法(POST、PUT/PATCH 和 DELETE)。 不检查 GET 请求的真实性令牌。 为什么? 因为 HTTP 规范规定 GET 请求是幂等的,并且不应该在服务器上创建、更改或销毁资源,并且该请求应该是幂等的(如果多次运行相同的命令,您应该得到每次都得到相同的结果)。
此外,真正的实现比一开始定义的要复杂一些,以确保更好的安全性。 Rails 不会为每个表单发出相同的存储令牌。 它也不会每次生成和存储不同的令牌。 它在会话中生成并存储加密哈希,并在每次呈现页面时发出新的加密令牌,该令牌可以与存储的加密令牌进行匹配。 请参阅 request_forgery_protection.rb。
经验教训
使用
authenticity_token
来保护您的非幂等方法(POST、PUT/PATCH 和 DELETE)。 还要确保不允许任何可能修改服务器上资源的 GET 请求。检查@erturne关于 GET 请求幂等的评论。 他以比我在这里所做的更好的方式解释了这一点。
What happens
When the user views a form to create, update, or destroy a resource, the Rails app creates a random
authenticity_token
, stores this token in the session, and places it in a hidden field in the form. When the user submits the form, Rails looks for theauthenticity_token
, compares it to the one stored in the session, and if they match the request is allowed to continue.Why it happens
Since the authenticity token is stored in the session, the client cannot know its value. This prevents people from submitting forms to a Rails app without viewing the form within that app itself.
Imagine that you are using service A, you logged into the service and everything is OK. Now imagine that you went to use service B, and you saw a picture you like, and pressed on the picture to view a larger size of it. Now, if some evil code was there at service B, it might send a request to service A (which you are logged into), and ask to delete your account, by sending a request to
http://serviceA.example/close_account
. This is what is known as CSRF (Cross Site Request Forgery).If service A is using authenticity tokens, this attack vector is no longer applicable, since the request from service B would not contain the correct authenticity token, and will not be allowed to continue.
API docs describes details about meta tag:
Notes
Keep in mind, Rails only verifies not idempotent methods (POST, PUT/PATCH and DELETE). GET request are not checked for authenticity token. Why? because the HTTP specification states that GET requests is idempotent and should not create, alter, or destroy resources at the server, and the request should be idempotent (if you run the same command multiple times, you should get the same result every time).
Also the real implementation is a bit more complicated as defined in the beginning, ensuring better security. Rails does not issue the same stored token with every form. Neither does it generate and store a different token every time. It generates and stores a cryptographic hash in a session and issues new cryptographic tokens, which can be matched against the stored one, every time a page is rendered. See request_forgery_protection.rb.
Lessons
Use
authenticity_token
to protect your not idempotent methods (POST, PUT/PATCH, and DELETE). Also make sure not to allow any GET requests that could potentially modify resources on the server.Check the comment by @erturne regarding GET requests being idempotent. He explains it in a better way than I have done here.
真实性令牌的设计是为了让您知道您的表单是从您的网站提交的。 它是从运行它的计算机生成的,具有只有您的计算机才能知道的唯一标识符,从而有助于防止跨站点请求伪造攻击。
如果您只是在 Rails 拒绝 AJAX 脚本访问时遇到困难,您可以
在创建表单时使用它来生成正确的令牌。
您可以在文档中了解更多相关信息。
The authenticity token is designed so that you know your form is being submitted from your website. It is generated from the machine on which it runs with a unique identifier that only your machine can know, thus helping prevent cross-site request forgery attacks.
If you are simply having difficulty with rails denying your AJAX script access, you can use
to generate the correct token when you are creating your form.
You can read more about it in the documentation.
什么是 CSRF?
真实性令牌是针对跨站点请求伪造 (CSRF) 的对策。 你问什么是 CSRF?
攻击者甚至可以在不知道会话令牌的情况下劫持会话。
场景:
CSRF 解决方案:
What is CSRF?
The Authenticity Token is a countermeasure to Cross-Site Request Forgery (CSRF). What is CSRF, you ask?
It's a way that an attacker can potentially hijack sessions without even knowing session tokens.
Scenario:
CSRF solution:
真实性令牌用于防止跨站点请求伪造攻击 (CSRF)。 要了解真实性令牌,必须首先了解 CSRF 攻击。
CSRF
假设您是
bank.example
的作者。 您的网站上有一个表单,用于通过 GET 请求将资金转入其他帐户:黑客只需向服务器发送 HTTP 请求即可
GET /transfer?amount= $1000000&account-to=999999
,对吗?错了。 黑客的攻击不会起作用。 服务器基本上会想什么?
服务器如何知道这一点? 因为没有
session_id
cookie 来验证请求者的身份。当您使用用户名和密码登录时,服务器会在您的浏览器上设置一个
session_id
cookie。 这样,您就不必使用您的用户名和密码来验证每个请求。 当您的浏览器发送session_id
cookie 时,服务器知道:黑客可能会想:
用户浏览器为
bank.example
域设置了一堆 cookie。 每次用户向bank.example
域发出请求时,所有 Cookie 都会一起发送。 包括session_id
cookie。因此,如果黑客可以让您发出 GET 请求,将资金转入他的帐户,那么他就成功了。 他怎么能骗你这么做呢?
通过跨站请求伪造。
实际上,这很简单。 黑客可能会让您访问他的网站。 在他的网站上,他可能有以下图像标签:
当用户浏览器遇到该图像标签时,它将向该 url 发出 GET 请求。 由于请求来自他的浏览器,因此它将发送与
bank.example
关联的所有 cookie。 如果用户最近登录了bank.example
...session_id
cookie 将被设置,服务器将认为用户打算将 1,000,000 美元转账到帐户 999999 !这还不够。 如果有人将该图像发布到 Facebook 并且它出现在您的墙上怎么办? 如果它被注入到您正在访问的遭受 XSS 攻击的网站怎么办?
不对。 可以动态生成发送 POST 请求的表单。 以下是Rails 安全指南中的示例:
真实性令牌
当您的
ApplicationController
具有以下内容时:This:
编译为以下内容:
特别是,会生成以下内容:
为了防止 CSRF 攻击,如果 Rails 没有看到随请求一起发送的真实性令牌,它不会认为该请求是安全的。
攻击者如何知道这个令牌是什么? 每次生成表单时都会随机生成不同的值:
跨站脚本 (XSS) 攻击 - 就是这样。 但这是不同日子的不同漏洞。
The authenticity token is used to prevent Cross-Site Request Forgery attacks (CSRF). To understand the authenticity token, you must first understand CSRF attacks.
CSRF
Suppose that you are the author of
bank.example
. You have a form on your site that is used to transfer money to a different account with a GET request:A hacker could just send an HTTP request to the server saying
GET /transfer?amount=$1000000&account-to=999999
, right?Wrong. The hackers attack won't work. The server will basically think?
How does the server know this? Because there's no
session_id
cookie authenticating the requester.When you sign in with your username and password, the server sets a
session_id
cookie on your browser. That way, you don't have to authenticate each request with your username and password. When your browser sends thesession_id
cookie, the server knows:A hacker might think:
The users browser has a bunch of cookies set for the
bank.example
domain. Every time the user makes a request to thebank.example
domain, all of the cookies get sent along. Including thesession_id
cookie.So if a hacker could get you to make the GET request that transfers money into his account, he'd be successful. How could he trick you into doing so?
With Cross Site Request Forgery.
It's pretty simply, actually. The hacker could just get you to visit his website. On his website, he could have the following image tag:
When the users browser comes across that image tag, it'll be making a GET request to that url. And since the request comes from his browser, it'll send with it all of the cookies associated with
bank.example
. If the user had recently signed in tobank.example
... thesession_id
cookie will be set, and the server will think that the user meant to transfer $1,000,000 to account 999999!That isn't enough. What if someone posts that image to Facebook and it appears on your wall? What if it's injected into a site you're visiting with a XSS attack?
Not true. A form that sends a POST request can be dynamically generated. Here's the example from the Rails Guide on Security:
Authenticity Token
When your
ApplicationController
has this:This:
Is compiled into this:
In particular, the following is generated:
To protect against CSRF attacks, if Rails doesn't see the authenticity token sent along with a request, it won't consider the request safe.
How is an attacker supposed to know what this token is? A different value is generated randomly each time the form is generated:
A Cross Site Scripting (XSS) attack - that's how. But that's a different vulnerability for a different day.
可以防止的最小攻击示例:CSRF
在我的网站上
evil.example
我说服您提交以下表单:如果您通过会话 cookie 登录到您的银行,那么cookie 将会在您不知情的情况下被发送并进行转移。
这就是 CSRF 令牌发挥作用的时候:
那么真实浏览器上的表单将如下所示:
因此,我的攻击将失败,因为它没有发送
authenticity_token
参数,而且我不可能猜到它,因为它是一个巨大的随机数。这种预防技术称为同步器令牌模式。
同源策略
但是,如果攻击者使用 JavaScript 发出两个请求,一个请求读取令牌,第二个请求进行转账,该怎么办?
仅同步器令牌模式不足以防止这种情况!
这就是同源策略发挥作用的地方,正如我在以下位置所解释的: https://security.stackexchange.com/questions/8264/why-is-the-same-origin-policy-so-important/72569#72569
Rails 如何发送令牌
涵盖于:Rails:csrf_meta_tag如何工作?< /a>
基本上:
如果不是 GET 表单,
像
form_tag
这样的 HTML 助手会为您在表单中添加一个隐藏字段AJAX 由 jquery-ujs,它从
csrf_meta_tags
添加到标头的meta
元素中读取令牌(存在于默认模板),并将其添加到发出的任何请求中。uJS 还尝试更新过时的缓存片段中表单中的令牌。
其他预防方法
X-Requested-With
:Origin
标头的值:https://security.stackexchange.com/questions/91165/why-is-the-synchronizer-token-pattern-preferred-over-the-origin-header-check-toMinimal attack example that would be prevented: CSRF
On my website
evil.example
I convince you to submit the following form:If you are logged into your bank through session cookies, then the cookies would be sent and the transfer would be made without you even knowing it.
That is were the CSRF token comes into play:
So the form on an authentic browser would look like:
Thus, my attack would fail, since it was not sending the
authenticity_token
parameter, and there is no way I could have guessed it since it is a huge random number.This prevention technique is called Synchronizer Token Pattern.
Same Origin Policy
But what if the attacker made two requests with JavaScript, one to read the token, and the second one to make the transfer?
The synchronizer token pattern alone is not enough to prevent that!
This is where the Same Origin Policy comes to the rescue, as I have explained at: https://security.stackexchange.com/questions/8264/why-is-the-same-origin-policy-so-important/72569#72569
How Rails sends the tokens
Covered at: Rails: How Does csrf_meta_tag Work?
Basically:
HTML helpers like
form_tag
add a hidden field to the form for you if it's not a GET formAJAX is dealt with automatically by jquery-ujs, which reads the token from the
meta
elements added to your header bycsrf_meta_tags
(present in the default template), and adds it to any request made.uJS also tries to update the token in forms in outdated cached fragments.
Other prevention approaches
X-Requested-With
:Origin
header: https://security.stackexchange.com/questions/91165/why-is-the-synchronizer-token-pattern-preferred-over-the-origin-header-check-toAuthenticity Token
是 Rails 的方法,用于防止 < a href="http://en.wikipedia.org/wiki/Cross-site_request_forgery#Example_and_characteristics" rel="noreferrer">“跨站点请求伪造(CSRF 或 XSRF)攻击”。简而言之,它确保对 Web 应用程序的 PUT / POST / DELETE(可以修改内容的方法)请求是从客户端的浏览器发出的,而不是从有权访问所创建的 cookie 的第三方(攻击者)发出的在客户端。
The
Authenticity Token
is rails' method to prevent 'cross-site request forgery (CSRF or XSRF) attacks'.To put it simple, it makes sure that the PUT / POST / DELETE (methods that can modify content) requests to your web app are made from the client's browser and not from a third party (an attacker) that has access to a cookie created on the client side.
因为 Authenticity Token 非常重要,并且在 Rails 3.0+ 中您可以使用它
创建
在任何地方
since
Authenticity Token
is so important, and in Rails 3.0+ you can useto create
anywhere
请注意,如果同一客户端有多个并发请求,真实性令牌机制可能会导致竞争条件。 在这种情况下,您的服务器可以生成多个真实性令牌,而实际上应该只有一个令牌,并且以表单形式接收较早令牌的客户端将在下一个请求中失败,因为会话 cookie 令牌已被覆盖。
这里有一篇关于这个问题的文章和一个不完全微不足道的解决方案:
http://www.paulbutcher.com /2007/05/race-conditions-in-rails-sessions-and-how-to-fix-them/
Beware the Authenticity Token mechanism can result in race conditions if you have multiple, concurrent requests from the same client. In this situation your server can generate multiple authenticity tokens when there should only be one, and the client receiving the earlier token in a form will fail on it's next request because the session cookie token has been overwritten.
There is a write up on this problem and a not entirely trivial solution here:
http://www.paulbutcher.com/2007/05/race-conditions-in-rails-sessions-and-how-to-fix-them/
需要
authenticity_token
的方法为什么需要它
Methods Where
authenticity_token
is requiredWhy It is Required
什么是authentication_token?
这是rails应用程序使用的随机字符串,用于确保用户是从应用程序页面而不是从其他应用程序或站点请求或执行操作。
为什么需要authentication_token?
保护您的应用或网站免遭跨站请求伪造。
如何将authentication_token添加到表单?
如果您使用form_for标签生成表单,则会自动添加authentication_token,否则您可以使用
<%= csrf_meta_tag %>
。What is an authentication_token ?
This is a random string used by rails application to make sure that the user is requesting or performing an action from the app page, not from another app or site.
Why is an authentication_token is necessary ?
To protect your app or site from cross-site request forgery.
How to add an authentication_token to a form ?
If you are generating a form using form_for tag an authentication_token is automatically added else you can use
<%= csrf_meta_tag %>
.在 Ruby on Rails 中,真实性令牌通常称为 CSRF(跨站点请求伪造)令牌,是一种安全功能,用于保护 Web 应用程序免受某些类型的攻击,特别是 CSRF 攻击。
In Ruby on Rails, the authenticity token, often referred to as the CSRF (Cross-Site Request Forgery) token, is a security feature used to protect web applications from certain types of attacks, particularly CSRF attacks.