Новое в Symfony 7.1: Атрибут IsCsrfTokenValid
- Pull Request: [Security][SecurityBundle] Add #[IsCsrfTokenValid] attribute #52961 Yassine Guedidi
- Pull Request: [Security] Add support for dynamic CSRF id with Expression in #[IsCsrfTokenValid] #54443 Yassine Guedidi
Атаки CSRF (Подделка межсайтовых запросов) используются злоумышленниками, чтобы заставить ваших легитимных пользователей отправлять данные неосознанно. В Symfony мы обеспечиваем полную защиту от CSRF-атак благодаря компоненту SecurityCsrf.
Ниже приведён распространённый фрагмент кода, используемый в контроллерах, расширяющих AbstractController
Symfony, для проверки валидности CSRF-токена формы:
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
class BlogPostController extends AbstractController
{
// ...
public function delete(): Response
{
if (!$this->isCsrfTokenValid('delete_example', $request->request->getString('_token'))) {
throw new BadRequestHttpException('This token is invalid');
}
// ...
}
}
В Symfony 7.1 вводится новый атрибут #[IsCsrfTokenValid]
, упрощающий этот код:
// ...
use Symfony\Component\Security\Http\Attribute\IsCsrfTokenValid;
class BlogPostController
{
// ...
#[IsCsrfTokenValid('delete_example')]
public function delete(): Response
{
// ...
}
}
Другая распространённая потребность — проверка нескольких одинаковых CSRF-токенов. Например, в списке статей блога каждая из них имеет немного отличающуюся форму удаления:
{% for post in blog_posts %}
{# ... #}
<form action="{{ path('post_delete', {post: post.id}) }}" method="POST">
<input type="hidden" name="_token" value="{{ csrf_token('delete-post-' ~ post.id) }}">
</form>
{% endfor %}
Эту проблему также можно решить с помощью атрибута #[IsCsrfTokenValid]
, поскольку он поддерживает выражения, совместимые с компонентом ExpressionLanguage:
// ...
use Symfony\Component\ExpressionLanguage\Expression;
class BlogPostController
{
// ...
#[IsCsrfTokenValid(new Expression('"delete-post-" ~ args["post"].id'))]
public function delete(Request $request, Post $post): Response
{
// ...
}
}