Защита от подделки межсайтовых запросов

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

Первая защита от атак CSRF - гарантировать, что запросы GET (и другие «безопасные» методы, как определено RFC 7231 # section-4.2.1 ) не имеют побочных эффектов. Запросы через «небезопасные» методы, такие как POST, PUT и DELETE, можно защитить, выполнив следующие действия.

Как пользоваться

Чтобы воспользоваться преимуществами защиты CSRF в ваших представлениях, выполните следующие действия:

  1. По умолчанию промежуточное ПО CSRF активировано в MIDDLEWARE настройках. Если вы переопределите этот параметр, помните, что он 'django.middleware.csrf.CsrfViewMiddleware'должен быть перед любым промежуточным программным обеспечением просмотра, которое предполагает, что CSRF-атаки были устранены.

    Если вы отключили его, что не рекомендуется, вы можете использовать его csrf_protect()в определенных представлениях, которые хотите защитить (см. Ниже).

  2. В любом шаблоне, который использует форму POST, используйте csrf_tokenтег внутри <form>элемента, если форма предназначена для внутреннего URL-адреса, например:

    <form method="post">{% csrf_token %}
    

    Этого не следует делать для форм POST, нацеленных на внешние URL-адреса, поскольку это приведет к утечке токена CSRF, что приведет к уязвимости.

  3. В соответствующих функциях просмотра убедитесь, что RequestContextон используется для рендеринга ответа, чтобы он работал правильно. Если вы используете функцию, общие представления или приложения contrib, вы уже защищены, поскольку все они используют .{% csrf_token %}render()RequestContext

AJAX

Хотя указанный выше метод может использоваться для запросов AJAX POST, он имеет некоторые неудобства: вы должны не забывать передавать токен CSRF как данные POST с каждым запросом POST. По этой причине существует альтернативный метод: для каждого XMLHttpRequest установите настраиваемый X-CSRFTokenзаголовок (как указано в CSRF_HEADER_NAMEнастройке) на значение токена CSRF. Часто это проще, потому что многие фреймворки JavaScript предоставляют перехватчики, которые позволяют устанавливать заголовки для каждого запроса.

Во-первых, вы должны получить токен CSRF. Как это сделать, зависит от того , или нет , CSRF_USE_SESSIONSи CSRF_COOKIE_HTTPONLYвключены настройки.

Установка токена на запрос AJAX

Наконец, вам нужно установить заголовок в своем запросе AJAX. Используя API fetch () :

const request = new Request(
    /* URL */,
    {headers: {'X-CSRFToken': csrftoken}}
);
fetch(request, {
    method: 'POST',
    mode: 'same-origin'  // Do not send CSRF token to another domain.
}).then(function(response) {
    // ...
});

Использование CSRF в шаблонах Jinja2

Бэкэнд Jinja2шаблонов Django добавляет контекст всех шаблонов, что эквивалентно языку шаблонов Django. Например:{{ csrf_input }}{% csrf_token %}

<form method="post">{{ csrf_input }}

Метод декоратора

Вместо того, чтобы добавлять CsrfViewMiddlewareв качестве общей защиты, вы можете использовать csrf_protectдекоратор, который имеет точно такие же функциональные возможности, для определенных представлений, которые нуждаются в защите. Его необходимо использовать как в представлениях, которые вставляют токен CSRF в вывод, так и в тех, которые принимают данные формы POST. (Часто это одна и та же функция просмотра, но не всегда).

Использовать декоратор сам по себе не рекомендуется , поскольку, если вы забудете его использовать, у вас будет дыра в безопасности. Стратегия «пояс и подтяжки» с использованием обоих подходов хороша и потребует минимальных накладных расходов.

csrf_protect( просмотр )

Декоратор, обеспечивающий защиту CsrfViewMiddlewareвида.

Применение:

from django.shortcuts import render
from django.views.decorators.csrf import csrf_protect

@csrf_protect
def my_view(request):
    c = {}
    # ...
    return render(request, "a_template.html", c)

Если вы используете представления на основе классов, вы можете обратиться к разделу «Украшение представлений на основе классов» .

Отклоненные запросы

По умолчанию пользователю отправляется ответ «403 Forbidden», если входящий запрос не прошел проверки, выполненные CsrfViewMiddleware. Обычно это следует видеть только при наличии подлинной подделки межсайтового запроса или когда из-за ошибки программирования токен CSRF не был включен в форму POST.

Однако страница ошибок не очень удобна, поэтому вы можете предоставить собственное представление для обработки этого условия. Для этого установите CSRF_FAILURE_VIEWнастройку.

Сбои CSRF регистрируются в журнале django.security.csrf как предупреждения .

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

Защита CSRF основана на следующем:

  1. Файл cookie CSRF, основанный на случайном секретном значении, к которому другие сайты не будут иметь доступа.

    Этот файл cookie установлен CsrfViewMiddleware. Он отправляется с каждым вызванным ответом django.middleware.csrf.get_token()(функция, используемая внутри для получения токена CSRF), если он еще не был установлен в запросе.

    Для защиты от атак BREACH токен - это не просто секрет; к секрету добавляется случайная маска, которая используется для его шифрования.

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

  2. Скрытое поле формы с именем csrfmiddlewaretoken, присутствующее во всех исходящих формах POST. Значение этого поля, опять же, является значением секрета с маской, которая добавляется к нему и используется для его шифрования. Маска восстанавливается при каждом вызове, get_token()так что значение поля формы изменяется в каждом таком ответе.

    Эта часть выполняется тегом шаблона.

  3. Для всех входящих запросов, которые не используют HTTP GET, HEAD, OPTIONS или TRACE, должен присутствовать файл cookie CSRF, а поле csrfmiddlewaretoken должно присутствовать и быть правильным. В противном случае пользователь получит ошибку 403.

    При проверке значения поля csrfmiddlewaretoken только секрет, а не полный токен, сравнивается с секретом в значении файла cookie. Это позволяет использовать постоянно меняющиеся токены. Хотя каждый запрос может использовать свой собственный токен, секрет остается общим для всех.

    Эта проверка выполняется CsrfViewMiddleware.

  4. Кроме того, для запросов HTTPS строгая проверка ссылки выполняется с помощью CsrfViewMiddleware. Это означает, что даже если поддомен может устанавливать или изменять файлы cookie в вашем домене, он не может заставить пользователя публиковать сообщения в вашем приложении, поскольку этот запрос не будет поступать из вашего собственного домена.

    Это также относится к атаке «человек посередине», которая возможна при использовании HTTPS при использовании секрета, не зависящего от сеанса, из-за того, что HTTP- Set-Cookieзаголовки (к сожалению) принимаются клиентами, даже когда они общаются с сайтом по HTTPS. (Проверка ссылок не выполняется для HTTP-запросов, потому что наличие Refererзаголовка недостаточно надежно для HTTP.)

    Если CSRF_COOKIE_DOMAINпараметр установлен, референт сравнивается с ним. Вы можете разрешить запросы между субдоменами, добавив точку в начале. Например, разрешит запросы POST от и . Если параметр не установлен, то ссылка должна соответствовать заголовку HTTP .CSRF_COOKIE_DOMAIN = '.example.com'www.example.comapi.example.comHost

    Расширение допустимых рефереров за пределы текущего хоста или домена cookie можно выполнить с помощью этой CSRF_TRUSTED_ORIGINSнастройки.

Это гарантирует, что только формы, созданные из доверенных доменов, могут быть использованы для возврата данных POST.

Он намеренно игнорирует запросы GET (и другие запросы, которые определены как «безопасные» RFC 7231 # раздел-4.2.1 ). Эти запросы никогда не должны иметь потенциально опасных побочных эффектов, поэтому CSRF-атака с запросом GET должна быть безвредной.RFC 7231 # section-4.2.1 определяет POST, PUT и DELETE как «небезопасные», и все другие методы также считаются небезопасными для максимальной защиты.

Защита CSRF не может защитить от атак типа «злоумышленник в середине», поэтому используйте HTTPS с HTTP Strict Transport Security . Он также предполагает проверку заголовка HOST и отсутствие на вашем сайте каких - либо уязвимостей межсайтового скриптинга (поскольку уязвимости XSS уже позволяют злоумышленнику делать все, что позволяет уязвимость CSRF, и намного хуже).

Удаление Refererзаголовка

Чтобы избежать раскрытия URL-адреса реферера сторонним сайтам, вы можете отключить реферер в <a>тегах вашего сайта . Например, вы можете использовать тег или включить заголовок. Из-за строгой проверки реферера защиты CSRF для запросов HTTPS эти методы вызывают сбой CSRF для запросов с «небезопасными» методами. Вместо этого используйте альтернативы, такие как ссылки на сторонние сайты.<meta name="referrer" content="no-referrer">Referrer-Policy: no-referrer<a rel="noreferrer" ...>"

Кеширование

Если csrf_tokenтег шаблона используется шаблоном (или get_tokenфункция вызывается другим способом), в ответ CsrfViewMiddlewareбудет добавлен файл cookie и заголовок. Это означает, что промежуточное программное обеспечение будет хорошо взаимодействовать с промежуточным программным обеспечением кеширования, если оно используется в соответствии с инструкциями ( идет раньше всех других промежуточных программ).Vary: CookieUpdateCacheMiddleware

Однако, если вы используете декораторы кеша для отдельных представлений, промежуточное ПО CSRF еще не сможет установить заголовок Vary или файл cookie CSRF, и ответ будет кэшироваться без них. В этом случае в любых представлениях, которые потребуют вставки токена CSRF, вы должны django.views.decorators.csrf.csrf_protect()сначала использовать декоратор:

from django.views.decorators.cache import cache_page
from django.views.decorators.csrf import csrf_protect

@cache_page(60 * 15)
@csrf_protect
def my_view(request):
    ...

Если вы используете представления на основе классов, вы можете обратиться к разделу «Украшение представлений на основе классов» .

Тестирование

CsrfViewMiddlewareОбычно будет большой помехой для тестирования функции представления , в связи с необходимостью для CSRF токена , который должен быть отправлен с каждым запросом POST. По этой причине HTTP-клиент Django для тестов был изменен, чтобы установить флаг для запросов, который ослабляет промежуточное программное обеспечение и csrf_protect декоратор, чтобы они больше не отклоняли запросы. Во всем остальном (например, отправка файлов cookie и т. Д.) Они ведут себя одинаково.

Если по какой-то причине вы хотите, чтобы тестовый клиент выполнял проверки CSRF, вы можете создать экземпляр тестового клиента, который выполняет проверки CSRF:

>>> from django.test import Client
>>> csrf_client = Client(enforce_csrf_checks=True)

Ограничения

Субдомены на сайте смогут устанавливать файлы cookie на клиенте для всего домена. Установив файл cookie и используя соответствующий токен, поддомены смогут обойти защиту CSRF. Единственный способ избежать этого - убедиться, что поддомены контролируются доверенными пользователями (или, по крайней мере, не могут устанавливать файлы cookie). Обратите внимание, что даже без CSRF существуют другие уязвимости, такие как фиксация сеанса, из-за которых предоставление субдоменов ненадежным сторонам является плохой идеей, и эти уязвимости нелегко исправить с помощью текущих браузеров.

Пограничные случаи

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

Утилиты

В приведенных ниже примерах предполагается, что вы используете представления на основе функций. Если вы работаете с представлениями на основе классов, вы можете обратиться к разделу «Украшение представлений на основе классов» .

csrf_exempt( просмотр )

Этот декоратор отмечает, что представление освобождается от защиты, обеспечиваемой промежуточным программным обеспечением. Пример:

from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def my_view(request):
    return HttpResponse('Hello world')
requires_csrf_token( просмотр )

Обычно csrf_tokenтег шаблона не работает, если не запущен CsrfViewMiddleware.process_viewаналогичный аналог csrf_protect. Декоратор представления requires_csrf_tokenможет использоваться для проверки работы тега шаблона. Этот декоратор работает аналогично csrf_protect, но никогда не отклоняет входящий запрос.

Пример:

from django.shortcuts import render
from django.views.decorators.csrf import requires_csrf_token

@requires_csrf_token
def my_view(request):
    c = {}
    # ...
    return render(request, "a_template.html", c)

Этот декоратор заставляет представление отправлять файл cookie CSRF.

Сценарии

Защита CSRF должна быть отключена только для нескольких просмотров

Большинство представлений требует защиты CSRF, но некоторые нет.

Решение: вместо того, чтобы отключать промежуточное программное обеспечение и применять его csrf_protectко всем представлениям, которые в нем нуждаются, включите промежуточное программное обеспечение и используйте csrf_exempt().

CsrfViewMiddleware.process_view не используется

Бывают случаи, когда CsrfViewMiddleware.process_viewможет не выполняться до запуска вашего представления - например, обработчики 404 и 500 - но вам все равно нужен токен CSRF в форме.

Решение: использовать requires_csrf_token()

Незащищенному представлению нужен токен CSRF

Могут быть некоторые представления, которые не защищены и были исключены csrf_exempt, но все же должны включать токен CSRF.

Решение: используйте с csrf_exempt()последующим requires_csrf_token(). (т.е. requires_csrf_token должен быть самым внутренним декоратором).

View нуждается в защите для одного пути

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

Решение: использовать csrf_exempt()для всей функции просмотра и csrf_protect()для пути внутри нее, который требует защиты. Пример:

from django.views.decorators.csrf import csrf_exempt, csrf_protect

@csrf_exempt
def my_view(request):

    @csrf_protect
    def protected_path(request):
        do_something()

    if some_condition():
       return protected_path(request)
    else:
       do_something_else()

Страница использует AJAX без HTML-формы

Страница выполняет запрос POST через AJAX, и на странице нет HTML-формы с, csrf_tokenкоторая могла бы вызвать отправку необходимого файла cookie CSRF.

Решение: используйте ensure_csrf_cookie()в представлении, которое отправляет страницу.

Contrib и многоразовые приложения

Поскольку разработчик может отключить CsrfViewMiddleware, все соответствующие представления в приложениях contrib используют csrf_protectдекоратор для обеспечения защиты этих приложений от CSRF. Рекомендуется, чтобы разработчики других многоразовых приложений, которым нужны такие же гарантии, также использовали csrf_protectдекоратор для своих представлений.

Настройки

Для управления поведением CSRF Django можно использовать ряд настроек:

Часто задаваемые вопросы

Является ли публикация произвольной пары токенов CSRF (данные cookie и POST) уязвимостью?

Нет, это сделано намеренно. Без атаки типа «человек посередине» злоумышленник не сможет отправить файл cookie с токеном CSRF в браузер жертвы, поэтому для успешной атаки потребуется получить файл cookie браузера жертвы с помощью XSS или аналогичного средства, и в этом случае злоумышленнику обычно не нужны CSRF-атаки.

Некоторые инструменты аудита безопасности отмечают это как проблему, но, как упоминалось ранее, злоумышленник не может украсть файл cookie CSRF браузера пользователя. «Кража» или изменение вашего собственного токена с помощью Firebug, инструментов разработчика Chrome и т. Д. Не является уязвимостью.

Проблема в том, что защита Django от CSRF по умолчанию не связана с сеансом?

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

Если вы хотите сохранить токен CSRF в сеансе пользователя, используйте CSRF_USE_SESSIONSпараметр.

Почему пользователь может столкнуться с ошибкой проверки CSRF после входа в систему?

По соображениям безопасности токены CSRF меняются каждый раз, когда пользователь входит в систему. Любая страница с формой, созданной до входа в систему, будет иметь старый, недопустимый токен CSRF, и ее необходимо будет перезагрузить. Это может произойти, если пользователь нажмет кнопку «Назад» после входа в систему или войдет в другую вкладку браузера.

Copyright ©2021 All rights reserved