Ruby-on-rails 了解 Rails 真实性令牌

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/941594/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 21:18:46  来源:igfitidea点击:

Understanding the Rails Authenticity Token

ruby-on-railsrubyauthenticity-token

提问by Ricardo Acras

I am running into some issues regarding the Authenticity Token in Rails, as I have many times now.

我遇到了一些关于 Rails 中 Authenticity Token 的问题,就像我现在遇到的很多次一样。

But I really don't want to just solve this problem and go on. I would really like to understand the Authenticity token. Well, my question is, do you have some complete source of information on this subject or would you spend your time to explain in details here?

但我真的不想只是解决这个问题然后继续下去。我真的很想了解真实性令牌。好吧,我的问题是,您是否有关于这个主题的完整信息来源,或者您会花时间在这里详细解释吗?

回答by Faisal

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 the authenticity_token, compares it to the one stored in the session, and if they match the request is allowed to continue.

当用户查看表单以创建、更新或销毁资源时,Rails 应用程序会创建一个 random authenticity_token,将此令牌存储在会话中,并将其放置在表单中的隐藏字段中。当用户提交表单时,Rails 查找authenticity_token,将其与会话中存储的进行比较,如果匹配,则允许请求继续。

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.com/close_account. This is what is known as CSRF (Cross Site Request Forgery).

由于真实性令牌存储在会话中,因此客户端无法知道其值。这可以防止人们在不查看应用程序本身内的表单的情况下向 Rails 应用程序提交表单。想象一下,您正在使用服务 A,您登录该服务并且一切正常。现在假设你去使用服务 B,你看到一张你喜欢的图片,然后按下图片查看更大尺寸的图片。现在,如果服务 B 中存在一些恶意代码,它可能会向服务 A(您已登录)发送请求,并通过向 发送请求来要求删除您的帐户http://serviceA.com/close_account。这就是所谓的CSRF(跨站点请求伪造)

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.

如果服务 A 使用真实性令牌,则此攻击向量不再适用,因为来自服务 B 的请求将不包含正确的真实性令牌,并且将不允许继续。

API docsdescribes details about meta tag:

API 文档描述了有关元标记的详细信息:

CSRF protection is turned on with the protect_from_forgerymethod, which checks the token and resets the session if it doesn't match what was expected. A call to this method is generated for new Rails applications by default. The token parameter is named authenticity_tokenby default. The name and value of this token must be added to every layout that renders forms by including csrf_meta_tagsin the HTML head.

CSRF 保护通过该protect_from_forgery方法打开,该方法检查令牌并在它与预期不匹配时重置会话。默认情况下,会为新的 Rails 应用程序生成对该方法的调用。令牌参数authenticity_token默认命名。必须将此标记的名称和值添加到通过包含csrf_meta_tags在 HTML 头中来呈现表单的每个布局。

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 notcreate, 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).

请记住,Rails 只验证不是幂等的方法(POST、PUT/PATCH 和 DELETE)。不检查 GET 请求的真实性令牌。为什么?因为GET请求的HTTP规范状态是幂等,应该不是创建,修改,或在服务器破坏资源,并且请求应该是幂等(如果您运行相同的命令多次,你应该每次都得到相同的结果)。

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.

此外,真正的实现比开始时定义的要复杂一些,以确保更好的安全性。Rails 不会为每个表单发出相同的存储令牌。它也不会每次都生成和存储不同的令牌。它在会话中生成并存储加密哈希,并在每次呈现页面时发布新的加密令牌,这些令牌可以与存储的令牌进行匹配。请参阅request_forgery_protection.rb

Lessons

教训

Use authenticity_tokento 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.

使用authenticity_token来保护您不幂等的方法(POST,PUT / PATCH和DELETE)。还要确保不允许任何可能修改服务器资源的 GET 请求。



EDIT:Check the comment by @erturneregarding GET requests being idempotent. He explains it in a better way than I have done here.

编辑:检查@erturne关于 GET 请求是幂等的评论。他以比我在这里所做的更好的方式解释了它。

回答by Topher Fangio

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

如果您只是在 Rails 拒绝您的 AJAX 脚本访问方面遇到困难,您可以使用

<%= form_authenticity_token %>

to generate the correct token when you are creating your form.

在创建表单时生成正确的令牌。

You can read more about it in the documentation.

您可以在文档中阅读更多相关信息。

回答by Rose Perrone

What is CSRF?

什么是CSRF?

The Authenticity Token is a countermeasure to Cross-Site Request Forgery (CSRF). What is CSRF, you ask?

真实性令牌是对跨站点请求伪造 (CSRF) 的一种对策。你问什么是CSRF?

It's a way that an attacker can potentially hiHyman sessions without even knowing session tokens.

这是攻击者可能在不知道会话令牌的情况下劫持会话的一种方式。

Scenario:

场景

  • Visit your bank's site, log in.
  • Then visit the attacker's site (e.g. sponsored ad from an untrusted organization).
  • Attacker's page includes form with same fields as the bank's "Transfer Funds" form.
  • Attacker knows your account info, and has pre-filled form fields to transfer money from your account to attacker's account.
  • Attacker's page includes Javascript that submits form to your bank.
  • When form gets submitted, browser includes your cookies for the bank site, including the session token.
  • Bank transfers money to attacker's account.
  • The form can be in an iframe that is invisible, so you never know the attack occurred.
  • This is called Cross-Site Request Forgery (CSRF).
  • 访问您的银行网站,登录。
  • 然后访问攻击者的站点(例如来自不受信任组织的赞助广告)。
  • 攻击者的页面包含与银行的“转移资金”表单具有相同字段的表单。
  • 攻击者知道您的帐户信息,并预先填写了表单字段以将资金从您的帐户转移到攻击者的帐户。
  • 攻击者的页面包含向您的银行提交表单的 Javascript。
  • 当表单被提交时,浏览器会包含银行网站的 cookie,包括会话令牌。
  • 银行将钱转入攻击者的账户。
  • 表单可以位于不可见的 iframe 中,因此您永远不知道发生了攻击。
  • 这称为跨站点请求伪造 (CSRF)。

CSRF solution:

CSRF 解决方案

  • Server can mark forms that came from the server itself
  • Every form must contain an additional authentication token as a hidden field.
  • Token must be unpredictable (attacker can't guess it).
  • Server provides valid token in forms in its pages.
  • Server checks token when form posted, rejects forms without proper token.
  • Example token: session identifier encrypted with server secret key.
  • Rails automatically generates such tokens: see the authenticity_token input field in every form.
  • 服务器可以标记来自服务器本身的表单
  • 每个表单都必须包含一个额外的身份验证令牌作为隐藏字段。
  • 令牌必须是不可预测的(攻击者无法猜测)。
  • 服务器在其页面的表单中提供有效的令牌。
  • 服务器在表单发布时检查令牌,拒绝没有正确令牌的表单。
  • 示例令牌:使用服务器密钥加密的会话标识符。
  • Rails 会自动生成这样的令牌:查看每个表单中的authenticity_token 输入字段。

回答by Adam Zerner

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)。要了解真实性令牌,您必须首先了解 CSRF 攻击。

CSRF

CSRF

Suppose that you are the author of bank.com. You have a form on your site that is used to transfer money to a different account with a GET request:

假设您是 的作者bank.com。您的网站上有一个表单,用于通过 GET 请求将资金转入其他帐户:

enter image description here

在此处输入图片说明

A hacker could just send an HTTP request to the server saying GET /transfer?amount=$1000000&account-to=999999, right?

黑客可以向服务器发送一个 HTTP 请求,说GET /transfer?amount=$1000000&account-to=999999,对吧?

enter image description here

在此处输入图片说明

Wrong. The hackers attack won't work. The server will basically think?

错误的。黑客攻击是行不通的。服务器基本上会怎么想?

Huh? Who is this guy trying to initiate a transfer. It's not the owner of the account, that's for sure.

嗯?这个试图发起转移的人是谁。它不是帐户的所有者,这是肯定的。

How does the server know this? Because there's no session_idcookie authenticating the requester.

服务器如何知道这一点?因为没有session_id验证请求者的cookie。

When you sign in with your username and password, the server sets a session_idcookie on your browser. That way, you don't have to authenticate each request with your username and password. When your browser sends the session_idcookie, the server knows:

当您使用您的用户名和密码登录时,服务器会session_id在您的浏览器上设置一个cookie。这样,您就不必使用用户名和密码对每个请求进行身份验证。当您的浏览器发送session_idcookie 时,服务器知道:

Oh, that's John Doe. He signed in successfully 2.5 minutes ago. He's good to go.

哦,那是约翰·多伊。他在 2.5 分钟前成功登录。他很高兴去。

A hacker might think:

黑客可能会想:

Hmm. A normal HTTP request won't work, but if I could get my hand on that session_idcookie, I'd be golden.

唔。普通的 HTTP 请求是行不通的,但如果我能拿到那个session_idcookie,我会很高兴的。

The users browser has a bunch of cookies set for the bank.comdomain. Every time the user makes a request to the bank.comdomain, all of the cookies get sent along. Including the session_idcookie.

用户浏览器为bank.com域设置了一堆 cookie 。每次用户向bank.com域发出请求时,所有 cookie 都会一起发送。包括session_id饼干。

So if a hacker could get youto 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.

因此,如果黑客可以让发出 GET 请求,将资金转入他的帐户,他就会成功。他怎么能骗你这样做?使用跨站点请求伪造。

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:

其实很简单。黑客可以让你访问他的网站。在他的网站上,他可能有以下图片标签:

<img src="http://bank.com/transfer?amount=00000&account-to=999999">

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.com. If the user had recently signed in to bank.com... the session_idcookie will be set, and the server will think that the user meant to transfer $1,000,000 to account 999999!

当用户浏览器遇到该图像标签时,它将向该 url 发出 GET 请求。并且由于请求来自他的浏览器,它会随同发送所有与bank.com. 如果用户最近登录bank.com... session_idcookie 将被设置,服务器将认为用户打算将 1,000,000 美元转移到帐户 999999!

enter image description here

在此处输入图片说明

Well, just don't visit dangerous sites and you'll be fine.

好吧,只是不要访问危险的网站,你会没事的。

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?

这还不够。如果有人将该图片发布到 Facebook 并且它出现在您的墙上怎么办?如果它通过 XSS 攻击被注入到您正在访问的站点中怎么办?

It's not so bad. Only GET requests are vulnerable.

也不是那么坏。只有 GET 请求易受攻击。

Not true. A form that sends a POST request can be dynamically generated. Here's the example from the Rails Guide on Security:

不对。可以动态生成发送 POST 请求的表单。以下是Rails 安全指南中的示例:

<a href="http://www.harmless.com/" onclick="
  var f = document.createElement('form');
  f.style.display = 'none';
  this.parentNode.appendChild(f);
  f.method = 'POST';
  f.action = 'http://www.example.com/account/destroy';
  f.submit();
  return false;">To the harmless survey</a>

Authenticity Token

真品令牌

When your ApplicationControllerhas this:

当你ApplicationController有这个时:

protect_from_forgery with: :exception

This:

这个:

<%= form_tag do %>
  Form contents
<% end %>

Is compiled into this:

编译成这样:

<form accept-charset="UTF-8" action="/" method="post">
  <input name="utf8" type="hidden" value="&#x2713;" />
  <input name="authenticity_token" type="hidden" value="J7CBxfHalt49OSHp27hblqK20c9PgwJ108nDHX/8Cts=" />
  Form contents
</form>

In particular, the following is generated:

特别是,生成以下内容:

<input name="authenticity_token" type="hidden" value="J7CBxfHalt49OSHp27hblqK20c9PgwJ108nDHX/8Cts=" />

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.

为了防止 CSRF 攻击,如果 Rails 没有看到与请求一起发送的真实性令牌,它不会认为请求是安全的。

How is an attacker supposed to know what this token is? A different value is generated randomly each time the form is generated:

攻击者应该如何知道这个令牌是什么?每次生成表单时都会随机生成一个不同的值:

enter image description here

在此处输入图片说明

A Cross Site Scripting (XSS) attack - that's how. But that's a different vulnerability for a different day.

跨站点脚本 (XSS) 攻击 - 就是这样。但对于不同的日子,这是一个不同的漏洞。

回答by andi

The Authenticity Tokenis rails' method to prevent'cross-site request forgery (CSRF or XSRF) attacks'.

防止“跨站点请求伪造(CSRF 或 XSRF)攻击”Authenticity Tokenis rails 方法。

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.

简而言之,它确保对您的 Web 应用程序的 PUT / POST / DELETE(可以修改内容的方法)请求是从客户端的浏览器发出的,而不是来自有权访问创建的 cookie 的第三方(攻击者)在客户端。

回答by Yuan He

since Authenticity Tokenis so important, and in Rails 3.0+ you can use

因为Authenticity Token非常重要,在 Rails 3.0+ 中你可以使用

 <%= token_tag nil %>

to create

创造

<input name="authenticity_token" type="hidden" value="token_value">

anywhere

任何地方

回答by jdp

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 机制可能会导致竞争条件。在这种情况下,您的服务器可以生成多个真实性令牌,而应该只有一个,并且客户端接收表单中较早的令牌将在其下一个请求中失败,因为会话 cookie 令牌已被覆盖。这里有一篇关于这个问题的文章和一个并非完全微不足道的解决方案:http: //www.paulbutcher.com/2007/05/race-conditions-in-rails-sessions-and-how-to-fix-them/

回答by uma

Methods Where authenticity_tokenis required

方法authenticity_token需要的地方

authenticity_tokenis required in case of idempotent methods like post, put and delete, Because Idempotent methods are affecting to data.

authenticity_token在 post、put 和 delete 等幂等方法的情况下需要,因为幂等方法会影响数据。

Why It is Required

为什么需要它

It is required to prevent from evil actions. authenticity_token is stored in session, whenever a form is created on web pages for creating or updating to resources then a authenticity token is stored in hidden field and it sent with form on server. Before executing action user sent authenticity_token is cross checked with authenticity_tokenstored in session. If authenticity_tokenis same then process is continue otherwise it does not perform actions.

需要防止恶行。真实性令牌存储在会话中,每当在网页上创建用于创建或更新资源的表单时,真实性令牌存储在隐藏字段中,并与服务器上的表单一起发送。在执行用户发送的操作之前,authenticity_token 会与authenticity_token存储在会话中的进行交叉检查。如果authenticity_token相同,则继续处理,否则不执行操作。

回答by Pradeep Sapkota

What is an authentication_token ?

什么是 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.

这是 rails 应用程序使用的随机字符串,用于确保用户是从应用程序页面请求或执行操作,而不是从其他应用程序或站点。

Why is an authentication_token is necessary ?

为什么需要 authentication_token ?

To protect your app or site from cross-site request forgery.

保护您的应用程序或站点免受跨站点请求伪造。

How to add an authentication_token to a form ?

如何将 authentication_token 添加到表单?

If you are generating a form using form_for tag an authentication_token is automatically added else you can use <%= csrf_meta_tag %>.

如果您使用 form_for 标记生成表单,则会自动添加 authentication_token,否则您可以使用<%= csrf_meta_tag %>.