13

在 Rails 4 应用程序的同一页面上,我有一个

在头部:

<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="some_token" />

和身体以下:

<form action="/someaction" method="post">
<input name="utf8" type="hidden" value="&#x2713;" />
<input type="hidden" name="_method" value="patch" />
<input type="hidden" name="authenticity_token" value="another_token" />

js 调用需要 csrf 令牌。但是为什么form token 和csrf token 不一样呢?这两个令牌中的哪一个用于表单提交?

4

2 回答 2

12

我做了一些研究来回答你的问题,这里是结果。

首先,让我们看一下这部分:

<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="some_token" />

这部分是由方法csrf_meta_tags生成的。从源代码中我们可以看到:

  1. 的“内容”属性值<meta name="csrf-param" />取自request_forgery_protection_token,默认情况下是:authenticity_token

  2. “内容”属性值<meta name="csrf-token" />取自form_authenticity_token方法,其中令牌要么取自会话,要么生成。

现在让我们看看这部分:

<input type="hidden" name="authenticity_token" value="another_token" />

从源码我们可以看出:

  1. 这个隐藏的输入由extra_tags_for_form方法返回。
  2. 内部extra_tags_for_form调用token_tag方法。
  3. token_tag方法将令牌作为参数。
  4. tokenfor 的参数之前是从html_options_for_form方法中的form_tag方法的参数中token_tag提取的。options

因此,如果您没有手动将authenticity_token参数设置options为自定义令牌并且不满足导致将token值设置为 false 的条件(将在下面提到),token_tag则方法将接收并调用用于标签nil的相同form_authenticity_token<meta name="csrf-token" />方法创造。顺便说一句,对于name输入的填充属性,它还使用request_forgery_protection_token,在<meta name="csrf-param" />标签生成时使用。

并且因为这一切都发生在同一个请求中,form_authenticity_token所以在两种情况下调用方法都应该返回相同的结果。

这两个令牌中的哪一个用于表单提交?

在提交表单时,将使用来自隐藏输入的令牌。

<meta />也可以使用来自的令牌,但前提是满足以下所有条件(使方法token的参数token_tag设置为 false):

  1. :remote => true应该传入optionsform_tag
  2. embed_authenticity_token_in_remote_forms配置设置为假。
  3. authenticity_token没有传入options

但是为什么form token 和csrf token 不一样呢?

至于这个问题,可能是因为缓存的原因出现了这个问题。或者,如果您使用 Turbolinks gem,可能会导致此问题(如果您完全刷新页面并再次比较令牌,则可以检查此问题)。有关 Turbolinks 问题的更多信息,请查看此问题

于 2017-08-01T17:05:06.650 回答
0

这可能与另一个问题有关,我在其中留下了答案:

使用 turbolinks 和 ruby​​ on rails 时发生 CSRF 令牌错误

于 2021-10-24T18:10:45.650 回答