Django CsrfViewMiddleware и эксплуатируемый поддомен
Контекст (двойная отправка файлов cookie и поддоменов):
При использовании токена CSRF с файлом cookie для метода двойной отправки файлов cookie вы должны убедиться, что клиент, получающий файл cookie, может прочитать этот файл cookie, а затем добавить CSRFToken из него в заголовки будущих запросов к серверной части.
При создании интерфейса, который находится в другом (поддомене), чем серверная часть, вы должны указать атрибут domain
для файла cookie. Например, если интерфейс включен app.example.com, а серверная часть включена api.example.com , тогда domain
для файла cookie должно быть установлено значение example.com
, иначе app.example.com
не сможет прочитать CSRFToken из файла cookie.
Однако это создает уязвимость для использования поддоменов. В этой презентации от OWASP объясняется, как это работает. Насколько я понимаю, поскольку мы разрешаем поддоменам example.com
считывать файлы cookie, то вредоносный сайт, подобный evil.example.com
, может быть настроен на ложную установку файлов cookie CSRF в обход защиты CSRF с помощью метода двойной отправки файлов cookie.
Вопрос
У Django может быть защита для этого, но я с трудом могу найти какую-либо документацию по этому поводу. В частности, в нем есть этот CSRF_TRUSTED_ORIGINS
, используемый CsrfViewMiddleware
. Вот что говорится в документах:
CSRF_TRUSTED_ORIGINS
Список надежных источников для небезопасных запросов (например, POST).
Для запросов, содержащих заголовок Origin, защита CSRF в Django требует, чтобы заголовок соответствовал заголовку origin, присутствующему в заголовке Host.
Для безопасного небезопасного запроса, который не содержит заголовка Origin, в запросе должен быть заголовок Referer, соответствующий заголовку origin, представленному в заголовке Host.
Эти проверки предотвращают, например, успешное выполнение POST-запроса от subdomain.example.com в отношении api.example.com. Если вам нужны небезопасные запросы от разных источников, продолжая пример, добавьте 'https://subdomain.example.com' в этот список (и/или http://... если запросы исходят с небезопасной страницы).
Этот параметр также поддерживает поддомены, поэтому вы можете добавить "https://*.example.com", например, чтобы разрешить доступ со всех поддоменов example.com.
А перефразированная реализация в django.middleware
выглядит следующим образом:
class CsrfViewMiddleware(MiddlewareMixin):
def _check_referer(self, request):
referer = request.META.get("HTTP_REFERER")
if referer is None:
raise RejectRequest(REASON_NO_REFERER)
try:
referer = urlparse(referer)
except ValueError:
raise RejectRequest(REASON_MALFORMED_REFERER)
# Make sure we have a valid URL for Referer.
if "" in (referer.scheme, referer.netloc):
raise RejectRequest(REASON_MALFORMED_REFERER)
# Ensure that our Referer is also secure.
if referer.scheme != "https":
raise RejectRequest(REASON_INSECURE_REFERER)
if any(
is_same_domain(referer.netloc, host)
for host in self.csrf_trusted_origins_hosts
):
# Passes _check_referer
return
@cached_property
def csrf_trusted_origins_hosts(self):
return [
urlparse(origin).netloc.lstrip("*")
for origin in settings.CSRF_TRUSTED_ORIGINS
]
Достаточно ли включения домена frontends в CSRF_TRUSTED_ORIGINS
для защиты от попыток взлома с помощью поддомена?
OWASP объясняет метод "Двойной отправки файлов cookie с подписью", но это добавляет мне много дополнительных возможностей из-за того, как я настраиваю аутентификацию. В идеале я хочу просто полагаться на то, что django уже реализовал для защиты CSRF, если этого достаточно.