Django DRF - ручная проверка маркера CSRF
Я прочитал в документации, что DRF проверяет CSRF-токены только на аутентифицированных запросах, а представления при входе должны явно проверять CSRF-токен.
Проблема в том, как вручную проверить CSRF-токен?
В моем settings.py
:
MIDDLEWARE = [
...
"django.middleware.csrf.CsrfViewMiddleware",
...
]
Вот мое мнение:
from rest_framework.decorators import api_view
from django.http import JsonResponse
from django.views.decorators.csrf import get_token
# I have to manually generate the csrf token and put it in the response body, because I use react-native and that can't read the token from the 'Set-Cookie' header
@api_view(["GET"])
def user_info(request):
return JsonResponse({"csrf_token": get_token(request)})
@api_view(["POST"])
def login(request):
return JsonResponse({"foo": "bar"})
Когда я делаю POST-запрос во фронтенде и не предоставляю CSRF-токен, он должен завершиться неудачей, но на самом деле я получаю {"foo": "bar"}
JSON.
Я попробовал декораторы @csrf_protect
и @requires_csrf_token
, но запрос по-прежнему не проходит.
Я также пробовал это, но ошибка на required positional argument: 'get_response
CsrfViewMiddleware().process_view(request, None, (), {})
Если я передаю функцию в get_response
, эта функция никогда не вызывается:
def test_get_response(req):
breakpoint()
CsrfViewMiddleware(get_response=test_get_response).process_request(request)
Я проверил, что CSRF-токен не передается в заголовках, а не в куках, и я пробовал разные браузеры и режим инкогнито.
Как заставить мои api запросы не работать, если они не включают действительный CSRF токен?
У вас ошибка в этом импорте from django.views.decorators.csrf import get_token
. вы должны импортировать get_token
из django.middleware.csrf
.
согласно документации django и он вернет CSRF токен, необходимый для POST формы.
Ладно... через несколько кроличьих нор я нашел какое-то решение.
Django использует Double Submit Cookie
для проверки CSRF. Это означает:
- Фронтенд запрашивает CSRF-токен у Django .
- Django генерирует токен, отправляет его FE в заголовке
Set-Cookie
- FE помещает csrf в cookie, который не может быть изменен потенциальным злоумышленником
- FE помещает тот же токен в POST форму и отправляет ее в Django .
- Django проверяет, совпадают ли токен в POST форме и cookie .
Проблема в том, что React Native не поддерживает cookies, поэтому приходится отправлять CSRF-токен другим способом. Проблема в том, что нет способа сделать это безопасно.
Я решил эту проблему, написав пользовательское промежуточное ПО для django:
- FE запрашивает CSRF-токен у Django
- Django генерирует токен, отправляет его FE, И сохраняет хэшированную версию в базе данных
- FE помещает его в POST форму и отправляет в Django
- Django хэширует токен, проверяет, есть ли хэш в db .
- После успешной валидации Django удаляет токен из базы данных .
- Задание CRON удаляет все неиспользованные токены через 24 часа
Немного громоздко, но мне приходится проверять таким образом только веб-запросы.