Rails authenticity_token 在表单上与 csrf 令牌
Rails authenticity_token on a form vs csrf token
在 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="✓" />
<input type="hidden" name="_method" value="patch" />
<input type="hidden" name="authenticity_token" value="another_token" />
js 调用需要 csrf 令牌。但为什么表单令牌与 csrf 令牌不同?提交表单时使用了这两个标记中的哪一个?
我做了一些研究来回答你的问题,这里是结果。
首先我们来看这部分:
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="some_token" />
这部分是由方法csrf_meta_tags生成的。从源码中我们可以看出:
"content" <meta name="csrf-param" />
的属性值取自 request_forgery_protection_token,默认情况下为 :authenticity_token
.
"content" <meta name="csrf-token" />
的属性值取自 form_authenticity_token 方法,其中令牌要么取自会话,要么生成。
现在让我们看看这部分:
<input type="hidden" name="authenticity_token" value="another_token" />
从源码中我们可以看出:
- 这个隐藏的输入是 return 通过 extra_tags_for_form 方法编辑的。
- 在
extra_tags_for_form
内部调用 token_tag 方法。
token_tag
方法将令牌作为参数。
token
token_tag
的参数先前是从 form_tag method in html_options_for_form 方法的 options
参数中提取的。
因此,如果您没有手动将 options
中的 authenticity_token
参数设置为您的自定义令牌,并且不满足导致将 token
值设置为 false 的条件(将将在下面提到),token_tag
方法将接收 nil
并调用用于创建 <meta name="csrf-token" />
标记的相同 form_authenticity_token 方法。顺便说一句,为了填充输入的 name
属性,它还使用 request_forgery_protection_token,即在 <meta name="csrf-param" />
标记生成发生时使用。
因为这一切都发生在同一个请求中,所以调用 form_authenticity_token
方法在两种情况下应该 return 相同的结果。
Which of the two tokens is used on form submission?
提交表单时将使用来自隐藏输入的令牌。
来自 <meta />
的令牌也可以使用,但前提是以下所有 conditions(使 token_tag
方法的 token
参数设置为 false)才会遇见:
:remote => true
应在 form_tag
的 options
中传递。
embed_authenticity_token_in_remote_forms
配置设置为 false。
authenticity_token
未在 options
中传递。
But why is the form token different from the csrf token?
至于这个问题,可能是缓存的问题。或者,如果您使用 Turbolinks gem,可能会导致此问题(如果您完全刷新页面并再次比较令牌,则可以检查此问题)。有关 Turbolinks 问题的更多信息,请查看 this question。
这可能与我留下答案的另一个问题有关:
在 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="✓" />
<input type="hidden" name="_method" value="patch" />
<input type="hidden" name="authenticity_token" value="another_token" />
js 调用需要 csrf 令牌。但为什么表单令牌与 csrf 令牌不同?提交表单时使用了这两个标记中的哪一个?
我做了一些研究来回答你的问题,这里是结果。
首先我们来看这部分:
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="some_token" />
这部分是由方法csrf_meta_tags生成的。从源码中我们可以看出:
"content"
<meta name="csrf-param" />
的属性值取自 request_forgery_protection_token,默认情况下为:authenticity_token
."content"
<meta name="csrf-token" />
的属性值取自 form_authenticity_token 方法,其中令牌要么取自会话,要么生成。
现在让我们看看这部分:
<input type="hidden" name="authenticity_token" value="another_token" />
从源码中我们可以看出:
- 这个隐藏的输入是 return 通过 extra_tags_for_form 方法编辑的。
- 在
extra_tags_for_form
内部调用 token_tag 方法。 token_tag
方法将令牌作为参数。token
token_tag
的参数先前是从 form_tag method in html_options_for_form 方法的options
参数中提取的。
因此,如果您没有手动将 options
中的 authenticity_token
参数设置为您的自定义令牌,并且不满足导致将 token
值设置为 false 的条件(将将在下面提到),token_tag
方法将接收 nil
并调用用于创建 <meta name="csrf-token" />
标记的相同 form_authenticity_token 方法。顺便说一句,为了填充输入的 name
属性,它还使用 request_forgery_protection_token,即在 <meta name="csrf-param" />
标记生成发生时使用。
因为这一切都发生在同一个请求中,所以调用 form_authenticity_token
方法在两种情况下应该 return 相同的结果。
Which of the two tokens is used on form submission?
提交表单时将使用来自隐藏输入的令牌。
来自 <meta />
的令牌也可以使用,但前提是以下所有 conditions(使 token_tag
方法的 token
参数设置为 false)才会遇见:
:remote => true
应在form_tag
的options
中传递。embed_authenticity_token_in_remote_forms
配置设置为 false。authenticity_token
未在options
中传递。
But why is the form token different from the csrf token?
至于这个问题,可能是缓存的问题。或者,如果您使用 Turbolinks gem,可能会导致此问题(如果您完全刷新页面并再次比较令牌,则可以检查此问题)。有关 Turbolinks 问题的更多信息,请查看 this question。
这可能与我留下答案的另一个问题有关: