Как CsrfViewMiddleware в Django защищает от CSRF-атак

Ответ

CsrfViewMiddleware — это встроенный в Django механизм защиты от атак типа "Межсайтовая подделка запроса" (Cross-Site Request Forgery). Атака заключается в том, что злоумышленник заставляет браузер аутентифицированного пользователя выполнить нежелательное действие на вашем сайте.

Механизм защиты (по шагам):

  1. Генерация токена: Для каждой пользовательской сессии Django генерирует уникальный секретный токен (csrf_token).
  2. Передача токена клиенту: Этот токен отправляется клиенту в виде cookie с именем csrftoken.
  3. Встраивание в формы: При рендеринге HTML-форм тег {% csrf_token %} добавляет в форму скрытое поле <input type='hidden' name='csrfmiddlewaretoken' value='...'> с этим же токеном.
  4. Проверка на сервере: При получении "небезопасного" запроса (POST, PUT, DELETE) middleware выполняет проверку:
    • Извлекает токен из cookie.
    • Извлекает токен из тела запроса (из скрытого поля).
    • Если токены не совпадают или отсутствуют, запрос отклоняется с ошибкой 403 Forbidden.

Почему это работает? Злоумышленник, разместив вредоносную форму на своем сайте, не имеет доступа к cookie вашего домена. Следовательно, он не может подставить в свой запрос правильный csrf_token, и атака проваливается.

Практическое применение:

  • Включение в settings.py:

    MIDDLEWARE = [
        # ...
        'django.middleware.csrf.CsrfViewMiddleware',
        # ...
    ]
  • Использование в шаблонах:

    <form method="post">
        {% csrf_token %}
        <!-- Поля формы -->
        <button type="submit">Отправить</button>
    </form>

AJAX-запросы: Для AJAX-запросов токен необходимо вручную извлекать из cookie и передавать в заголовке X-CSRFToken. Большинство JavaScript-фреймворков имеют для этого встроенные решения.

Ответ 18+ 🔞

Слушай, а вот этот CsrfViewMiddleware — это такая штука, которая в Django от одной конкретной хуйни защищает. От атаки, которая называется "Межсайтовая подделка запроса". Звучит сложно, а на деле — проще пареной репы, если не вдаваться в дебри.

Представь себе: ты залогинился на каком-нибудь банковском сайте, сессия живая, куки твои там болтаются. И тут ты, такой довольный, заходишь на другой сайт, где тебе какой-то мудак подсовывает красивую кнопочку "Получить миллион". А на самом деле эта кнопка — скрытая форма, которая шлёт запрос от твоего же лица в тот самый банк: "Перевести все деньги на счёт 12345". И браузер-то твой, дурак, выполнит этот запрос, потому что куки от банка у него есть! Вот это и есть CSRF — тебя, грубо говоря, подставляют.

А как Django с этим борется? Да очень просто, как топором по башке:

  1. Токен генерирует. Для каждой твоей сессии на сервере создаётся уникальный, ебаный секретный ключ — csrf_token.
  2. В печеньку суёт. Этот ключ тебе в браузер отправляется в виде куки с именем csrftoken.
  3. В форму прячет. Когда на сервере рисуется HTML-форма, волшебный тег {% csrf_token %} вставляет в неё скрытое поле: <input type='hidden' name='csrfmiddlewaretoken' value='...ТВОЙ_СЕКРЕТНЫЙ_КОД...'>.
  4. Проверяет, сволочь. Когда приходит "опасный" запрос (POST, PUT, DELETE), этот самый middleware встаёт на дыбы:
    • Достаёт токен из твоей куки.
    • Достаёт токен из тела запроса (из того самого скрытого поля).
    • Сравнивает. Если они одинаковые — ок, проходи. Если нет или чего-то не хватает — бац, 403 Forbidden, пошёл на хуй!

Почему это работает, блядь? Да потому что злоумышленник со своего левого сайта не может прочитать куки твоего банка! Он не может узнать этот секретный токен, чтобы подсунуть его в свою подставную форму. Вот и вся магия, ёпта.

Как этим пользоваться на практике?

  • В settings.py оно уже, скорее всего, стоит:

    MIDDLEWARE = [
        # ... куча другого middleware ...
        'django.middleware.csrf.CsrfViewMiddleware', # <- Вот этот красавец
        # ...
    ]
  • А в шаблоне форму просто обмазывай тегом:

    <form method="post">
        {% csrf_token %} <!-- Вот эта строчка — твой бронежилет -->
        <!-- Тут всякие поля: имя, пароль, сумма перевода -->
        <button type="submit">Отправить деньги</button>
    </form>

А что с AJAX-запросами? Там чуть замороченнее. Токен из кук надо самому вытащить и запихнуть в заголовок запроса X-CSRFToken. Но народ уже всё придумал, во всех популярных JS-фреймворках есть готовые решения, чтобы не ебать себе мозг каждый раз. Главное — не забывать это делать, а то будешь потом чесать репу, почему твой красивый аякс-запрос получает 403-ю ошибку.