Дата обновления перевода 2021-06-09

Как реализовать CSRF-защиту

CSRF - или Межсайтовая подделка запроса - это метод, которым недобросовестный пользователь пытается заставить ваших пользователей не зная об этом, отправлять данные, которые они не собирались отправлять.

Защита от CSRF работает путём добавления ввашу форму скрытого поля, которое содержит значение, которое знаете только вы и ваш пользователь. Это гарантирует, что пользователь - а не какая-то другая сущность - отправляет данные.

Перед использованием CSRF-защиты, установите её в вашем проекте:

1
$ composer require symfony/security-csrf

Затем, включитте/выключите CSRF-защиту с помощью опции csrf_protection (см. справочник конфигурации CSRF, чтобы узнать больше):

  • YAML
    1
    2
    3
    4
    # config/packages/framework.yaml
    framework:
        # ...
        csrf_protection: ~
    
  • XML
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    <!-- config/packages/framework.xml -->
    <?xml version="1.0" encoding="UTF-8" ?>
    <container xmlns="http://symfony.com/schema/dic/services"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:framework="http://symfony.com/schema/dic/symfony"
        xsi:schemaLocation="http://symfony.com/schema/dic/services
            http://symfony.com/schema/dic/services/services-1.0.xsd
            http://symfony.com/schema/dic/symfony
            http://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
    
        <framework:config>
            <framework:csrf-protection enabled="true" />
        </framework:config>
    </container>
    
  • PHP
    1
    2
    3
    4
    5
    6
    7
    8
    // config/packages/framework.php
    use Symfony\Config\FrameworkConfig;
    
    return static function (FrameworkConfig $framework) {
        $framework->csrfProtection()
            ->enabled(true)
        ;
    };
    

Токены, используемые для CSRF-защиты, должны быть разными для каждого пользователя, и они хранятся в сессии. Поэтому сессия начинается автоматически, как только вы отображаете форму с CSRF-защитой.

Более того, это означает, что вы не можете полностью кешировать страницы, которые имеют формы с защитой от CSRF. Как вариант, вы можете:

  • Встроить форму внутрь некешируемого фрагмента ESI и кешировать остаток содержания страницы;
  • Кешировать всю страницу и загрузить форму через некешируемый запрос AJAX;
  • Кешировать всю страницу и использовать hinclude.js для загрузки CSRF-токена с некешируемым запросом AJAX, и заменить значение поля формы им.

CSRF-защита в формах Symfony

Формы, созданные с помощью компонента Symfony Форма включают в себя токены CSRF по умолчанию, и Symfony проверяет их автоматически, так что вам не нужно ничего делать, чтобы быть защищёнными от CSRF атак.

По умолчанию, Symfony добавляет CSRF токен в скрытое поле под названием _token, но это можно настраивать от формы к форме:

// src/Form/TaskType.php
namespace App\Form;

// ...
use App\Entity\Task;
use Symfony\Component\OptionsResolver\OptionsResolver;

class TaskType extends AbstractType
{
    // ...

    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'data_class'      => Task::class,
            // включить/выключить защиту от CSRF для этой формы
            'csrf_protection' => true,
            // имя скрытого HTML поля, хранящего токен
            'csrf_field_name' => '_token',
            // произвольная строка, использовання для генерирования значения токена,
            // использование другой строки для каждой формы усиливает её безопасность
            'csrf_token_id'   => 'task_item',
        ]);
    }

    // ...
}

Вы также можете настроить отображение поля формы CSRF, создав пользовательскую тему формы и используя csrf_token в качестве префикса поля (например, определить {% block csrf_token_widget %} ... {% endblock %}, чтобы настроить все содержание поля формы).

CSRF-защита в формах входа в систему

См. How to Build a Login Form, чтобы увидеть форму входа в систему, которая защищена от CSRF-атак. Вы также можете сконфигурировать CSRF-защиту для действия выхода из системы.

Генерирование и проверка CSRF-токенов вручную

Хотя Формы Symfony предоставляют автоматическую CSRF-защиту по умолчанию, вам может понадобиться сгенерировать и проверить CSRF-токены вручную, например, при использовании обычных HTML-форм, не управляемыъ компонентом Symfony Формы.

Рассмотрите HTML-форму, созданную для позволения удаления объектов. Для начала, используйте функцию Twig csrf_token(), чтобы сгенерировать CSRF-токен в шаблоне и сохранить его в скрытом поле формы:

1
2
3
4
5
6
<form action="{{ url('admin_post_delete', { id: post.id }) }}" method="post">
    {# аргумент csrf_token() это произвольная строка. используемая для генерирования токена #}
    <input type="hidden" name="token" value="{{ csrf_token('delete-item') }}"/>

    <button type="submit">Delete item</button>
</form>

Затем, получите значение CSRF-токена в действии контроллера и используйте isCsrfTokenValid(), чтобы проверить его валидность:

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
// ...

public function delete(Request $request): Response
{
    $submittedToken = $request->request->get('token');

    // 'delete-item' это то же значение, что используется в шаблоне для генерирования токена
    if ($this->isCsrfTokenValid('delete-item', $submittedToken)) {
        // ... сделайте что-то, вроде удаления объекта
    }
}

CSRF-токены и сжатие атак по сторонним каналам

BREACH и CRIME - это эксплойты безопасности против HTTPS при использовании сжатия HTTP. Хакеры могут использовать информацию, упущенную во время сжатия, чтобы восстановить целевые части открытого текста. Чтобы ослабить эти атаки, и предупредить хакера от укгадывания CSRF-токенов, к началу токена добавляется рандомная маска, которая используется для его перемешивания.

New in version 5.3: Рандомизация токенов была представлена в Symfony 5.3

Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.