我创建了一个Symfony2表单并将其绑定到Request。在继续处理表单的其余部分之前,我需要明确确保CSRF令牌是否有效/无效。
$form['_token']->isValid()
抛出OutOfBoundsException
,并显示消息“Child _token不存在。”
我仍然可以验证呈现的表单是否包含_token
字段。如果CSRF值无效,$form->isValid()
将返回false。
我在这里缺少什么?
更新1:
控制器(部分):
private function buildTestForm() {
$form = $this->createFormBuilder()
->add('name','text')
->getForm();
return $form;
}
/**
* @Route("/test/show_form", name="test.form.show")
* @Method("GET")
*/
public function showFormTest()
{
$form = $this->buildTestForm();
return $this->render('TestBundle::form_test.html.twig', array('form' => $form->createView()));
}
/**
* @Route("/test/submit_form", name="test.form.submit")
* @Method("POST")
*/
public function formTest()
{
$form = $this->buildTestForm();
$form->bind($this->getRequest());
if ($form['_token']->isValid()) {
return new Response('_token is valid');
} else {
return new Response('_token is invalid');
}
}
模板
{# Twig template #}
<form action="{{ path('test.form.submit') }}" method="post" {{ form_enctype(form) }}>
{{ form_widget(form) }}
<input type="submit" name="go" value="Test Form" />
</form>
答案 0 :(得分:11)
没有记录的方法来手动检查csrf令牌。 Symfony会自动验证此令牌的存在和准确性。 http://symfony.com/doc/current/book/forms.html#csrf-protection
但是有一个csrf提供者:
和
标记能够提供CSRF保护的类您可以生成CSRF 使用generateCsrfToken()方法的token。对你这个方法 应该传递一个应该保护的页面唯一的值 反对CSRF攻击。该值不一定非必须 秘密。此接口的实现负责添加 更多秘密信息。
如果您想确保针对CSRF攻击的表单提交,那么您 可以提供“意图”字符串。这样你就可以确保了 表单只能绑定到旨在处理表单的页面, 也就是说,使用相同的意图字符串来验证CSRF令牌 与isCsrfTokenValid()。
您可以像这样检索提供商
$csrf = $this->get('form.csrf_provider');
使用然后可以使用
public Boolean isCsrfTokenValid(string $intention, string $token)
Validates a CSRF token.
参数string $ intention生成时使用的意图 CSRF令牌字符串$ token浏览器提供的令牌
返回值Boolean是否由浏览器提供的令牌 正确
您需要找出表单使用的意图字符串。
有关SO的一些有趣帖子:
答案 1 :(得分:11)
除了artworkad,您还可以指定意图:
嫩枝:
<form method="post">
<input type="text" name="form_name[field]" value="" />
<input type="hidden" name="_csrf_token" value="{{ csrf_token('form_name') }}">
</form>
PHP:
$token = $request->request->get('_csrf_token');
$csrf_token = new CsrfToken('form_name', $token);
var_dump($this->get('security.csrf.token_manager')->isTokenValid($csrf_token));
或不:
嫩枝:
<form method="post">
<input type="text" name="field" value="" />
<input type="hidden" name="_csrf_token" value="{{ csrf_token('') }}">
</form>
PHP:
$token = $request->request->get('_csrf_token');
$csrf_token = new CsrfToken('', $token);
var_dump($this->get('security.csrf.token_manager')->isTokenValid($csrf_token));
答案 2 :(得分:0)
我不确定这一点,但您是否在未映射的字段上尝试过验证器:
$violations = $this->get('validator')->validatePropertyValue($entity, '_token', $form['_token']);
if (count($violations)) {
// the property value is not valid
}
答案 3 :(得分:0)
另一种方法(如果您更喜欢DI)在控制器外部(例如在侦听器中)验证令牌:
/** @var Symfony\Component\Security\Csrf\CsrfTokenManagerInterface */
private $csrfTokenManager;
public __construct(CsrfTokenManagerInterface $csrfTokenManager)
{
$this->csrfTokenManager = $csrfTokenManager;
}
public function isValid(): bool
{
return $this->csrfTokenManager->isTokenValid(
new CsrfToken('authenticate', $request->getRequest()->headers->get('X-CSRF-TOKEN'))
);
}