CSRF 令牌无效。请尝试重新提交表单
Posted
技术标签:
【中文标题】CSRF 令牌无效。请尝试重新提交表单【英文标题】:The CSRF token is invalid. Please try to resubmit the form 【发布时间】:2014-06-20 18:28:06 【问题描述】:每次我尝试提交表单时都会收到此错误消息:
我的表单代码是这样的:
<form novalidate action="path('signup_index')" method="post" form_enctype(form) role="form" class="form-horizontal">
<div class="form-group">
form_label(form.email, 'Email', 'label_attr': 'class': 'col-md-1 control-label')
form_widget(form.email, 'attr': 'class': 'col-md-2')
form_errors(form.email)
</div>
<div class="form-group">
form_label(form.nickname, 'Nickname', 'label_attr': 'class': 'col-md-1 control-label')
form_widget(form.nickname, 'attr':'class': 'col-md-2')
form_errors(form.nickname, 'attr': 'class': 'col-md-3')
</div>
<div class="form-group">
form_label(form.password, 'password', 'label_attr': 'class': 'col-md-1 control-label')
form_widget(form.password, 'attr': 'class': 'col-md-2')
form_errors(form.password, 'attr': 'class': 'col-md-3')
</div>
<div class="form-group">
form_label(form.password_repeat, 'Repeat password', 'label_attr': 'class': 'col-md-1 control-label')
form_widget(form.password_repeat, 'attr':'class': 'col-md-2')
form_errors(form.password_repeat, 'attr': 'class': 'col-md-3')
</div>
<div class="form-group">
<div class="col-md-1 control-label">
<input type="submit" value="submit">
</div>
</div>
</form>
有什么想法吗?
【问题讨论】:
@MKhalidJunaid 你为什么要保护这个? 【参考方案1】:您需要在表单中添加_token
,即
form_row(form._token)
到目前为止,您的表单缺少 CSRF 令牌字段。如果您使用 twig 表单函数来呈现您的表单,例如 form(form)
,这将自动为您呈现 CSRF 令牌字段,但您的代码显示您正在使用原始 html 呈现表单,例如 <form></form>
,因此您必须手动呈现字段。
或者,只需在表单的结束标记前添加 form_rest(form)
。
根据文档
这会渲染给定的所有尚未渲染的字段 形式。始终将其放在表单中的某个地方是个好主意 因为它会为您呈现隐藏字段并制作您忘记的任何字段 渲染得更明显(因为它会为您渲染该字段)。
form_rest(view, variables)
【讨论】:
form_rest(form) 对我来说是最好的。谢谢,+1 @M Khalid Junaid 我有一个文件,并通过 symfony 表单组件呈现它。在树枝中获取令牌并在控制器中获取令牌值,但是总是得到相同的错误。 谢谢,在我的情况下,我有 form_end(form, 'render_rest': false)
,我之前为一些测试设置过。现在我把它改成普通的 form_end(form)
,它工作了。
如果您看到这篇文章,请记住该文档不包含此信息。我已经创建了 1 个 PR 来添加它,但我不知道我还能做些什么来帮助其他人,问候。 github.com/symfony/symfony-docs/pull/16321【参考方案2】:
当您的表单有很多元素时,您也会看到此错误消息。
php.ini 中这个选项导致问题的原因
; How many GET/POST/COOKIE input variables may be accepted
max_input_vars = 1000
问题是_token字段错过了PUT(GET)请求,所以你必须增加值。
另外,它涉及一个大文件。增加
upload_max_filesize
选项会解决问题。
【讨论】:
在我的例子中是 post_max_size + upload_max_filesize 我只在提交包含大量元素的表单时遇到问题。 将 max_input_vars 设置为更大的数字也为我修复了它。当您考虑它时,它是有道理的 - CSRF 令牌通常是呈现和发送的最后一个表单元素。当您有太多元素时“从请求中截断更多输入变量。”。所以 CSRF 令牌在到达 Symfony 时就已经丢失了。 (来源:php.net/manual/en/info.configuration.php#ini.max-input-vars)。 在调试了这个 csrf 错误 4 小时后,我在这里找到了答案。我的表格太大,没有发送 csrf。谢谢 在我的例子中,表单本身看起来并不是很大,但是有一个关系字段,有 100 个关系。【参考方案3】:这是因为表单默认包含 CSRF 保护,在某些情况下这不是必需的。
您可以在getDefaultOptions
方法中的表单类中禁用此 CSRF 保护,如下所示:
// Other methods omitted
public function getDefaultOptions(array $options)
return array(
'csrf_protection' => false,
// Rest of options omitted
);
如果您不想禁用 CSRF 保护,则需要在表单中呈现 CSRF 保护字段。可以通过在视图文件中使用 form_rest(form)
来完成,如下所示:
<form novalidate action="path('signup_index')" method="post" form_enctype(form) role="form" class="form-horizontal">
<!-- Code omitted -->
<div class="form-group">
<div class="col-md-1 control-label">
<input type="submit" value="submit">
</div>
</div>
form_rest(form)
</form>
form_rest(form)
会呈现您未手动输入的所有字段。
【讨论】:
“不必要”可能没问题,但有什么好的理由不保护每一个表格吗? @NicoHaase 是的,如果您构建无状态 API。您仍然可以使用 symfony 表单进行验证,并且不需要 CSRF 保护security.stackexchange.com/questions/166724/…【参考方案4】:在你的</form>
标签之前:
form_rest(form)
它会自动插入其他重要的(隐藏的)输入。
【讨论】:
【参考方案5】:我遇到了一个奇怪的问题:清除浏览器缓存并没有解决问题,但清除 cookie(即 PHP 会话 ID cookie)确实解决了这个问题。
这必须在您检查了所有其他答案后完成,包括验证您确实在隐藏的表单输入字段中拥有令牌。
【讨论】:
【参考方案6】:除了其他人的建议之外,如果您的会话存储不工作,您可能会收到 CSRF 令牌错误。
在最近的一个案例中,我的一位同事将 'session_prefix' 更改为一个包含空格的值。
session_prefix: 'My Website'
这破坏了会话存储,这反过来意味着我的表单无法从会话中获取 CSRF 令牌。
【讨论】:
一个相关的陷阱使您的控制器中的会话无效。【参考方案7】:如果您已将表单从纯 HTML 转换为 twig,请确保您没有错过删除结束 </form>
标记。愚蠢的错误,但我发现这可能是导致此问题的原因。
当我收到这个错误时,一开始我无法弄清楚。我使用form_start()
和form_end()
来生成表单,所以我不应该用form_row(form._token)
显式添加令牌,或者使用form_rest()
来获取它。 It should have already been added automatically by form_end()
.
问题是,我正在使用的视图是我从纯 HTML 转换为 twig 的视图,我错过了删除结束 </form>
标记,所以不是:
form_end(form)
我有:
</form>
form_end(form)
这实际上看起来可能会引发错误,但显然不会,所以当form_end()
输出form_rest()
时,表单已经关闭。表单实际生成的页面源是这样的:
<form>
<!-- all my form fields... -->
</form>
<input type="hidden" id="item__token" name="item[_token]" value="SQAOs1xIAL8REI0evGMjOsatLbo6uDzqBjVFfyD0PE4" />
</form>
显然解决方案是删除多余的结束标签,然后再喝点咖啡。
【讨论】:
【参考方案8】:我最近遇到了这个错误。原来我的 cookie 设置在 config.yml 中不正确。将cookie_path
和cookie_domain
设置添加到framework.session
修复了它。
【讨论】:
【参考方案9】:我最近也遇到了同样的问题,我的情况在这里还没有提到:
问题是我在localhost
域上测试它。我不确定这到底是为什么,但在我将localhost
的主机名别名添加到/etc/hosts
之后,它就开始起作用了:
127.0.0.1 foobar
在使用 Apache 和 localhost
作为域时,会话可能有问题。如果有人可以在 cmets 中详细说明,我很乐意编辑此答案以包含更多详细信息。
【讨论】:
【参考方案10】:如果您不想使用 form_row 或 form_rest 并且只想访问 _token 在您的 twig 模板中的值。使用以下内容:
<input type="hidden" name="form[_token]" value=" form._token.vars.value " />
【讨论】:
如果您这样做,请确保始终调用 % do form._token.setRendered % 否则如果您在某处有 form_rest 调用,您可能会得到两个令牌输入字段【参考方案11】:在我的例子中,我遇到了实体中的 maxSize 注释,因此我将它从 2048 增加到 20048。
/**
* @Assert\File(
* maxSize = "20048k",
* mimeTypes = "application/pdf", "application/x-pdf",
* mimeTypesMessage = "Please upload a valid PDF"
* )
*/
private $file;
希望这个答案有帮助!
【讨论】:
【参考方案12】:我遇到了类似的问题。在确保实际呈现了令牌字段(请参阅接受的答案)后,我检查了我的 cookie。 我的 Chrome 浏览器中的域有 2(!) 个 cookie,显然是因为我在与另一个应用程序相同的域上运行该应用程序,但使用不同的端口(即 mydomain.com 在有问题的应用程序运行时设置原始 cookie在 mydomain.com:123) 现在显然 Chrome 发送了错误的 cookie,因此 CSRF 保护无法将令牌链接到正确的会话。
修复:清除相关域的所有 cookie,确保您不在同一个域上使用不同端口运行多个应用程序。
【讨论】:
【参考方案13】:我遇到了同样的错误,但在我的情况下,问题是我的应用程序使用了多个一级域,而 cookie 使用了一个。从config.yml
中的framework.session
中删除cookie_domain: ".%domain%"
会导致cookie 默认为表单所在的任何域,从而解决了问题。
【讨论】:
【参考方案14】:你需要记住 CSRF 令牌是存储在 session 中的,所以这个问题也可能是由于无效的 session 处理而发生的。如果您在本地主机上工作,请检查例如如果会话 cookie 域设置正确(在 PHP 中,在本地主机上应该为空)。
【讨论】:
【参考方案15】:这似乎是使用引导程序时的一个问题,除非您通过 form(form) 呈现表单。此外,问题似乎只发生在输入类型=“隐藏”上。如果您使用表单检查页面,您会发现隐藏的输入根本不是标记的一部分,或者它正在呈现但由于某种原因未提交。如上所述,添加 form_rest(form) 或像下面这样包装输入应该可以解决问题。
<div class="form-group">
<input type="hidden" name="_csrf_token" value=" csrf_token('authenticate') ">
</div>
【讨论】:
以上是关于CSRF 令牌无效。请尝试重新提交表单的主要内容,如果未能解决你的问题,请参考以下文章
Symfony3 中的错误“CSRF 令牌无效。请尝试重新提交表单”
Ajax GET 请求后表单提交失败(无效的 CSRF 令牌)。怎么修?