在Symfony 2中存在某种方式在每次呈现表单时生成CSRF令牌? 在我的控制器中,我尝试过这样的事情:
$request = $this->get('request');
if ($request->getMethod() != 'POST') {
$csrf = $this->get('form.csrf_provider');
$date= new \DateTime("now");
$this->date = $date->format('Y-m-d H:i:s');
$token = $csrf->generateCsrfToken($this->date);
} elseif($request->getMethod() == "POST") {
$csrf = $this->get('form.csrf_provider');
$token = $csrf->generateCsrfToken($this->date);
}
$form = $this->createFormBuilder()
....
->add('_token','hidden',array(
'data' => $token
))->getForm();
if ($request->getMethod() == 'POST') {
$form->bindRequest($request);
if ($form->isValid()) {
DO something
}
}
所有时间都在我的请求权限令牌哈希中。但是在bindRequest之后,它更改为从parameters.ini和isValid方法中的安全字符串生成的默认哈希值,肯定会返回FALSE响应。存在某种方式,如何调整它?
修改 为了响应不尽人意的答案,我编辑了我的控制器并创建了我的CSRF提供程序,但仍然在发现“CSRF令牌无效。请尝试重新提交表单”错误。我的CSRF提供商看起来像这样:
namespace My\Namespace;
use Symfony\Component\HttpFoundation\Session;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
class MyCsrfProvider implements CsrfProviderInterface
{
protected $session;
protected $secret;
protected $datetime;
public function __construct(Session $session, $secret)
{
$this->secret = $secret;
$this->datetime = new \DateTime('now');
$this->session = $session;
}
public function generateCsrfToken($intention)
{
return sha1($this->secret.$intention.$this->datetime->format('YmdHis').$this->getSessionId());
}
public function isCsrfTokenValid($intention, $token)
{
return $token === $this->generateCsrfToken($intention);
}
protected function getSessionId()
{
return $this->session->getId();
}
}
比我添加到config.yml服务类:
services:
form.csrf_provider:
class: My\Namespace\MyCsrfProvider
arguments: [ @session, %kernel.secret% ]
控制器我改为:
//any form without _token field
$form = $this->createFormBuilder()
->add('field1')
->add('field2')->getForm()
if ($this->getRequest()->getMethod() == 'POST') {
$request = $this->getRequest();
$form->bindRequest($request);
if ($form->isValid()) {
Do something
return $this->redirect($this->generateUrl('somewhere'));
}
}
我的哈希在几秒钟内出现问题?如果我从日期时间格式中删除秒数,它会起作用,但是有1分钟到期并且它不是一个好的解决方案。我想,原因是时间已经改变了。
答案 0 :(得分:1)
Symfony的Form
组件在Form事件中生成CSRF令牌。有关现有实施的工作原理,请参阅课程Symfony\Component\Form\Extension\Csrf\EventListener\CsrfValidationListener
。这意味着当您在表单上调用bindRequest()
(或Symfony 2.2+中的bind()
)时,将调用该表单事件并覆盖您声明的令牌。
定义不同令牌的正确方法是创建CsrfProvider
,它基本上是您编写的实现Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface
的类。查看Symfony\Component\Form\Extension\Csrf\CsrfProvider\DefaultCsrfProvider以获取如何实现此目的的示例。
在您编写课程后,在app/config/parameters.yml
(或其他配置文件中,无关紧要),将form.csrf_provider.class
参数设置为您班级的名称。
在完成所有这些之后,您应该能够删除从控制器中编写的所有自定义代码,并且只需使用表单系统,就好像没有任何不同(即删除->add('_token')...
部分)。
希望有所帮助!
答案 1 :(得分:-1)
您知道form_rest
吗?将其添加到表单底部,以使其自动生成CSRF令牌:
{{ form_rest(form) }}