Laravel CSRF: обзор понятий и реализаций защиты

Автор: | 25.08.2017

laravel-csrfЗдравствуйте, уважаемые посетители cccp-blog.com! Наконец, после трёхмесячного перерыва я снова возвращаюсь к творчеству и продолжаю цикл публикаций по созданию корпоративного сайта на Laravel.

Так что тех из вас, кто думал, что я позабыл про свои обещания довести сайт до конца, спешу «обрадовать» :-) А тем из вас, кто попал впервые на данных блог, рекомендую подписаться на обновления, чтобы увидеть, чем данный цикл в итоге всё-таки закончится.

Итак, в предыдущей статье я показал вам как создавать Laravel controllers и правила роутинга для указания обработчиков запросов, посылаемых на определённые url сайта.

Там же я пообещал в будущих статьях рассказать об особенностях реализации AJAX в Laravel на примере создания контактной формы.

Реализации я в итоге решил посвятить следующую статью, а в данной сказать пару слов об особенностях, главной из которых является реализация в Laravel защиты от CSRF-атак, которая на практике слегка мешает и напрягает неподготовленных разработчиков.

Поэтому сегодня речь пойдёт о реализации Laravel CSRF protection на сайте, а также о легальных способах её обхода в исключительных случаях.

Поехали :-)

СОДЕРЖАНИЕ

Что такое CSRF

Те из вас, кто интересовался когда-то кибербезопасностью и безопасностью сайтов, в частности, наверняка знаком термин с аббревиатурой CSRF, которая расшифровывается как «Cross Site Request Forgery».

Если вы знаете, что это, то просто можете пропустить первые три блока статьи. Для тех же, что не в курсе, сделаю небольшое пояснение.

Википедия, опуская дословный перевод, говорит о том, что CSRF — это межсайтовая подделка запроса, которая является одним из видов атак на посетителей веб-сайтов.

Она заключается в том, что хакеры, используя данные залогиненных пользователей в куках различных сайтов (начиная от банальных блогов, заканчивая сайтами банков), производят от их лица различные действия. Спрашивается, как хакеры узнают данные пользователей, чтобы отправить запрос от их имени?

Самое интересное, что ничего они не узнают :-) Пользователи сами же дают согласие на произведение действий, угодных хакерам.

Как работает CSRF

Всем вам, наверное, неоднократно приходили на почту письма с содержанием вида «Смотри, какие милые котики» или «Не думал, что ты такое способен. Смотри, что я нашёл» и какими-то левыми ссылками с зашифрованными url и текстом, побуждающим по ним перейти.

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

В результате у вас со счёта уйдут деньги в неизвестном направлении или появится комментарий с абсолютно произвольным содержанием на блоге.

Ну а что? Всё правильно. После обращения к администрации сайта люди там будут мягко говоря обескуражены. Действие от авторизованного в системе пользователя было, но он при этом утверждает, что ничего не делал. Мистика какая-то :-)

По логам атакуемого сайта будет видно, что пользователь сам отправил запрос, как бы он потом не доказывал, что это прошло случайно и его обманули.

Запрос прошёл проверку авторизации пользователя на сайте? Прошёл.

Получатель платежа и сумма были указаны? Были.

Даже IP адрес, с которого был произведён запрос, будет ваш же, т.к. вы сами нажали на ссылку.

Как уберечься от CSRF

Отсюда мораль: как пользователь, ни в коем случае не переходите ни по каким сомнительным ссылкам, особенно из писем в папке «Спам». Ну, а как разработчик, вы должны учитывать возможность данных атак на пользователей создаваемых вами сайтов и всячески их предотвращать.

Во-первых, самое простое, ни в коем случае не хранить данные авторизаций в куках браузера (для этого есть сессии на стороне сервера).

Во-вторых, важные действия (переводы денег, комментарии и т.д.) производить с помощью POST, PUT, DELETE, PATCH HTTP запросов, но никак не GET, HEAD, OPTIONS и TRACE. Так их сложнее будет подделать, т.к. отправить такой запрос с IP пользователя путём клика на ссылку не получится, адрес уже будет компьютера хакера, с которого он будет отправлять запрос, по которому его можно будет и вычислить (если он, конечно, не додумается его изменить или отправить запрос через прокси).

И, собственно говоря, вторая группа запросов предназначена для получения данных сайта, а не для изменения состояния сервера.

Ну, и третье, лучше при разработке пользоваться наработками опытных программистов, а лучше целых их команд, где обязательно должны быть специалисты по кибербезопасности.

Защита от CSRF в Laravel

К счастью, Laravel соответствует всем указанным выше требованиям. Поэтому, выбрав его, вы можете быть уверены, что данные ваших пользователей будут в полной безопасности. Осталось только научиться пользоваться методами Laravel CSRF protection.

А они достаточно просты и заключаются в указании CSRF токена при отправке запроса, который сверяется на сервере перед его обработкой.

CSRF token в Laravel представляет собой строку из 40 случайных символов (судя по коду Laravel 5.4, которым я в данный момент располагаю), который генерируется при создании новой сессии приложения, т.е. при активности нового пользователя на сайте.

Таким образом, проверка CSRF токена перед обработкой запроса позволяет выяснить, что данный запрос был отправлен конкретным пользователем, а не кем-то вместо него.

Если вы отправите запрос, скажем, через HTML форму методом POST, PUT, DELETE или PATCH, то получите следующую ошибку проверки CSRF:

laravel-oshibka-proverki-csrf-tokena

Чтобы запрос отправился, необходимо в форму, с помощью которой отправляется запрос, добавить скрытое поле со значением CSRF token с помощью специальной функции-хэлпера csfr_field следующим образом:


<form method="post">
    {{ csrf_field() }}
    ...
</form>

Кстати, данный хэлпер появился сравнительно недавно — в Laravel 5.1. Так что, если вы используете более раннюю версию, то можете воспользоваться следующей конструкцией вместо предложенной:

<input type="hidden" name="_token" value="{!! csrf_token() !!}">

Также разработчики Laravel рекомендуют для дополнительной защиты AJAX запросов добавлять CSRF токен ко всем запросам на уровне JavaScript путём указания токена в значении метатэга, размещённого в секции head HTML-документа:

<meta name="csrf-token" content="{{ csrf_token() }}">

Считывание данного значения в JS производится следующей JQuery-конструкцией:

$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});

При отправке же GET запроса для успешной его обработки сервером CSRF token указывать не нужно. Но, как известно, данный тип запроса и так считается небезопасным благодаря указанию параметров в URL запроса, которые можно увидеть в браузере. Поэтому пользоваться им для передачи конфиденциальных и важных данных не то, что не рекомендуется, а запрещается :-)

Кстати, текущий CSRF токен указывается в качестве значения переменной COOKIE X-XSRF-TOKEN, которая присутствует в каждом ответе сервера. Поэтому иногда его будет удобнее использовать, особенно в ситуациях, когда значение CSRF токена необходимо получить в JavaScript, где хэлперы Laravel, как известно, не работают.

Обход CSRF защиты

Иногда возникают ситуации, когда запрос нужно не проверять на наличие в его параметрах CSRF токена. Особенно это актуально при работе с различными сервисами по API, т.к. ресурсы не будут знать, какой CSRF токен отправить при посылке ответа Laravel сайту.

За чтение CSRF token и его проверку перед выполнением запроса ответственны, как ни странно, Laravel middleware, а именно VerifyCsrfToken.php, который и генерирует исключение (exception) при попытке отправить POST запрос без указания токена.

Мы можем им воспользоваться в случаях, когда нам необходимо будет обойти CSRF защиту (совершайте это действие крайне осознанно!), указав необходимые url в потомке оригинального core-вского VerifyCsrfToken.php класса App\Http\Middleware\VerifyCsrfToken следующим образом:


<?php

namespace App\Http\Middleware;

use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;

class VerifyCsrfToken extends BaseVerifier
{
    /**
     * The URIs that should be excluded from CSRF verification.
     *
     * @var array
     */
    protected $except = [
        //url запросов, для которых не нужно проверять CSRF токен
    ];
}

Вот и всё, что нужно для исключения url от проверки на CSRF безопасность.
И на этом данная статья подходит к концу. В следующей я покажу вам, как реализовывать в Laravel AJAX запросы с применением сегодняшних знаний.

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

На этом всё. Пока :-)

  1. 5
  2. 4
  3. 3
  4. 2
  5. 1
7 голосов, в среднем: 4.4 из 5

2 комментария к статье "Laravel CSRF: обзор понятий и реализаций защиты"

  1. Edred

    Спасибо, очень полезная информация, все изложено очень доходчиво!

    Только добавьте, плиз, частичку «не» перед словом «рекомендуется» в конце этого абзаца:
    «…При отправке же GET запроса для успешной его обработки сервером CSRF token указывать не нужно. Но, как известно, данный тип запроса и так считается небезопасным благодаря указанию параметров в URL запроса, которые можно увидеть в браузере. Поэтому пользоваться им для передачи конфиденциальных и важных данных не то, что рекомендуется, а запрещается.»

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *