Если вы пишете на Yii2, то наверняка слышали про XSS и CSRF. Звучит как что-то страшное из мира хакеров, правда? На самом деле это две самые распространенные уязвимости, через которые злоумышленники могут испортить вам жизнь — украсть данные пользователей, взломать админку или подменить контент. Но не переживайте: защититься от них проще, чем кажется. В этой статье я расскажу, как сделать ваше приложение крепким орешком, используя встроенные механизмы Yii2. Будет много практики, примеров и парочка лайфхаков.

Digital-студия WNDER

Почему XSS и CSRF — это боль, и как они работают

Давайте сразу разберемся, с чем мы имеем дело. XSS (Cross-Site Scripting) — это когда злоумышленник внедряет вредоносный скрипт прямо на вашу страницу. Например, через поле комментария. Вы этот скрипт не видите, но браузер выполняет его, и он может украсть куки, сессию или перенаправить пользователя на фишинговый сайт. CSRF (Cross-Site Request Forgery) — это когда от имени пользователя отправляется поддельный запрос. Представьте: вы залогинены в админке, а злоумышленник подсовывает вам ссылку, по которой вы случайно переходите, и в этот момент отправляется запрос на удаление базы данных. Вот такие дела.

В Yii2 уже есть встроенные инструменты для защиты от этих атак. Но если вы не будете их правильно использовать, они не сработают. Давайте посмотрим, как это делается.

Защита от XSS: экранирование и фильтрация

Первый шаг — научиться правильно выводить данные. Никогда не выводите пользовательский ввод без обработки. В Yii2 для этого есть хелпер Html::encode(). Он превращает специальные символы в HTML-сущности, и браузер не выполняет их как код.


// Плохо: выводим как есть
<?= $userInput ?>

// Хорошо: экранируем
<?= \yii\helpers\Html::encode($userInput) ?>

Но это только база. В Yii2 есть еще ActiveForm, которая автоматически экранирует значения полей. Если вы используете Html::textInput() или ActiveField, то значения будут безопасными. Но не забывайте про атрибуты HTML — например, title или alt. Их тоже нужно экранировать, иначе можно протащить скрипт через кавычки.

Еще один момент — фильтрация данных на входе. Не доверяйте ничему, что приходит от пользователя. Используйте правила валидации в моделях. Например, для строки можно задать filter — он автоматически применит trim или strip_tags.


public function rules()
{
    return [
        [['username'], 'filter', 'filter' => 'trim'],
        [['comment'], 'filter', 'filter' => 'strip_tags'],
    ];
}
Правило: всегда экранируйте вывод и фильтруйте ввод. Даже если данные приходят из базы, считайте их небезопасными. Лучше перебдеть, чем потом чистить последствия.

CSRF-защита: встроенные механизмы Yii2

Теперь про CSRF. В Yii2 защита включена по умолчанию, если в конфигурации приложения установлен параметр enableCsrfValidation в true. Это значит, что при отправке форм через ActiveForm автоматически добавляется скрытое поле с токеном. Но есть подводные камни.

Если вы используете обычные HTML-формы, не через ActiveForm, то токен нужно добавлять вручную. Иначе запрос будет отклонен. Вот как это сделать:


// В представлении
<form method="post">
    <?= \yii\helpers\Html::hiddenInput(Yii::$app->request->csrfParam, Yii::$app->request->csrfToken) ?>
    <!-- остальные поля -->
</form>

Для AJAX-запросов токен тоже нужен. Обычно его передают в заголовке X-CSRF-Token. В Yii2 можно настроить это глобально через конфигурацию:


'components' => [
    'request' => [
        'csrfParam' => '_csrf',
        'enableCsrfValidation' => true,
        'cookieValidationKey' => 'ваш-секретный-ключ',
    ],
],

Кстати, не забудьте установить cookieValidationKey — это ключ для шифрования куки, он должен быть уникальным для каждого приложения.

Практические советы для AJAX и REST API

Если ваше приложение использует AJAX-запросы, то нужно быть особенно внимательным. В Yii2 есть специальный компонент yii\web\Request, который проверяет токен. Но если вы делаете запросы через JavaScript, убедитесь, что токен отправляется вместе с запросом. Вот пример на jQuery:


$.ajax({
    url: '/site/delete',
    type: 'POST',
    data: {id: 123},
    headers: {
        'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
    },
    success: function(data) { console.log(data); }
});

Для этого в макете добавьте мета-тег с токеном:



Для REST API ситуация немного другая. Если ваш API использует токены авторизации, то CSRF-защита может мешать. В Yii2 можно отключить CSRF для отдельных контроллеров или действий, но делать это нужно осознанно. Например, для API-контроллеров, которые работают с Bearer-токенами, CSRF не нужен, потому что запросы идут с сервера на сервер. Но если вы отключаете защиту, убедитесь, что у вас есть другие механизмы проверки подлинности.

Ситуация Рекомендация
Обычные формы Используйте ActiveForm или добавляйте токен вручную
AJAX-запросы Передавайте токен в заголовке X-CSRF-Token
REST API Отключайте CSRF только если используете токены авторизации

Лайфхаки и типичные ошибки

Напоследок — несколько лайфхаков, которые помогут избежать граблей.

  • Не храните секретные ключи в коде — выносите их в файл конфигурации или в переменные окружения.
  • Используйте компонент Security для генерации случайных строк и хеширования паролей.
  • Проверяйте, что enableCsrfValidation не отключен случайно в конфигурации.
  • Для экранирования в JavaScript используйте json_encode() с флагом JSON_HEX_TAG — это защитит от XSS через JSON.
  • Не забывайте про валидацию данных на сервере, даже если на клиенте уже есть проверки.
Лайфхак: включите в конфигурации параметр 'enableCsrfValidation' => true, но для AJAX-запросов используйте функцию Yii::$app->request->csrfToken в JavaScript. Это сэкономит время и нервы.

И еще одна частая ошибка — забыть про экранирование в атрибутах HTML. Например:


// Плохо: title не экранирован
<?= Html::tag('div', $data, ['title' => $userInput]) ?>

// Хорошо: экранируем атрибут
<?= Html::tag('div', $data, ['title' => Html::encode($userInput)]) ?>

В Yii2 есть метод Html::escape(), который можно применить ко всему массиву атрибутов, но лучше делать это точечно.

Итоги: что запомнить

Безопасность — это не разовая акция, а постоянный процесс. Но базируясь на встроенных механизмах Yii2, вы можете значительно снизить риски. Главное — не лениться и следовать простым правилам:

  • Всегда экранируйте вывод и фильтруйте ввод.
  • Не отключайте CSRF-защиту без веской причины.
  • Используйте токены для AJAX и API.
  • Держите конфигурацию в секрете и обновляйте Yii2 до актуальной версии.

Если вы будете следовать этим советам, ваше приложение станет неприступной крепостью для большинства атак. И помните: безопасность — это не то, на чем стоит экономить. Лучше потратить час на настройку, чем потом разгребать последствия взлома.

Студия WNDER