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

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

Первая линия защиты от атак 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 внутри тега HTML, <form> если форма ссылается на внутренний URL-адрес, например:

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

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

  3. В соответствующих функциях просмотра проверьте, что RequestContext используется для создания ответа, чтобы он работал правильно. Если вы используете функцию , общие представления или дополнительные приложения, не нужно беспокоиться, потому что все эти представления используют .{% 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 для вашего домена, он не может заставить пользователя отправлять данные в ваше приложение, потому что этот запрос не будет исходить из вашего точного домена.

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

    Если настройка CSRF_COOKIE_DOMAIN определена, референт сравнивается с ней. Этот параметр учитывает поддомены. Например, разрешите POST-запросы от и . Если параметр не определен, реферер должен соответствовать заголовку HTTP .CSRF_COOKIE_DOMAIN = '.exemple.com' www.exemple.com api.exemple.com Host

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

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

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

Защита CRSF не может защитить от атак «злоумышленник посередине», поэтому HTTPS следует использовать со строгой безопасностью транспорта HTTP (HSTS) . Также предполагается, что заголовок HOST был проверен и что на сайте нет уязвимостей межсайтового скриптинга (поскольку этот тип уязвимости уже позволяет злоумышленнику делать то, что делает уязвимость 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: Cookie UpdateCacheMiddleware

Однако, если вы используете декораторы кеша для отдельных представлений, промежуточное ПО 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 и т. Д.) Поведение во время тестирования такое же.

Если по какой-то причине вы хотите, чтобы HTTP-клиент, используемый для тестирования, выполнял проверки 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 должен быть самым внутренним декоратором).

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

Вид нуждается в защите 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() в представлении, которое отправляет страницу.

Встроенные и многоразовые приложения

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

Настройки

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

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

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

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

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

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

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

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

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

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

Copyright ©2020 All rights reserved