React & Django - WARNING:django.request:Forbidden: /api/user - SessionAuthentication

Я создал этот Django & React проект (https://github.com/axilaris/docker-django-react-celery-redis), и у меня возникли трудности с доступом к API с SessionAuthentication. Вы можете легко протестировать и использовать мой код с помощью:

  • docker-compose build
  • docker-compose up

Я продолжаю получать проблемы с доступом к /api/user (вы можете проверить с помощью register, login)

backend_container   | Forbidden: /api/user
backend_container   | WARNING:django.request:Forbidden: /api/user

Вы можете посмотреть больше журналов здесь: https://gist.github.com/axilaris/7b7a5c50f4f7112b440eaf8ef8100d9d

In my django api code (backend/user_api/views.py):

    class UserView(APIView):
        permission_classes = (permissions.IsAuthenticated,)
        authentication_classes = (SessionAuthentication,)
        def get(self, request):
            serializer = UserSerializer(request.user)
            return Response({'user': serializer.data}, status=status.HTTP_200_OK)



In settings.py:

CORS_ALLOWED_ORIGINS = [
    'http://localhost',
    'http://127.0.0.1',
    'http://0.0.0.0',
]

CORS_ALLOW_CREDENTIALS = True

INSTALLED_APPS = [
..
    'corsheaders',
]


MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
...
]

and in react:
axios.defaults.xsrfCookieName = 'csrftoken';
axios.defaults.xsrfHeaderName = 'X-CSRFToken';
axios.defaults.withCredentials = true;

  useEffect(() => {
    client.get("/api/user")
    .then(function(res) {
      setCurrentUser(true);
    })
    .catch(function(error) {
      setCurrentUser(false);
    });
  }, []);

почему всякий раз, когда после входа в систему я перезагружаю localhost в браузере, он запрещает /api/user и возвращается на страницу входа. Я считаю, что CORS настроен правильно и учетные данные установлены как на бэкенде, так и на фронтенде.

У вас есть:

Client (React) --> [HTTP Request with CSRF Token] --> Django Backend
                                                  /\
                                                  |
                                                  +--- [Session Authentication & CSRF Validation]

Чтобы SessionAuthentication работал, убедитесь, что сессионный куки Django (sessionid) и куки CSRF-токена (csrftoken) правильно установлены и отправлены клиенту. Флаг HttpOnly обычно должен быть установлен в куках sessionid для повышения безопасности, как упоминалось в этой теме.

Поскольку сессионный cookie (sessionid) должен быть HttpOnly, приложение React не будет напрямую взаимодействовать с ним. Вместо этого убедитесь, что конфигурация axios правильно включает учетные данные при каждом запросе. Похоже, что в вашей установке эта часть настроена правильно (axios.defaults.withCredentials установлен на true).

settings.py должен включать в себя:

SESSION_COOKIE_HTTPONLY = True  # Default value is True, which is recommended
SESSION_COOKIE_SAMESITE = 'Lax' # Consider 'None' if strictly necessary and secure is set
SESSION_COOKIE_SECURE = True    # Set to True if you are using HTTPS

Для настройки CSRF-куки:

CSRF_COOKIE_HTTPONLY = False    # Should generally be False to allow JavaScript to read the value
CSRF_COOKIE_SECURE = True       # Set to True if you are using HTTPS

Установка CSRF_COOKIE_HTTPONLY в False сделает ваше приложение немного более уязвимым для XSS-атак, так как позволит JavaScript получить доступ к CSRF-куки. Лучшим подходом будет сохранение маркера CSRF HttpOnly и получение его из отдельной конечной точки API, предназначенной для явного возврата маркера CSRF, или включение маркера CSRF в тело страницы и считывание его оттуда вашим JavaScript.

Хотя... как документировано с 2016 года в django/django PR 7700 и commit c27104a

Обозначение CSRF-куки как HttpOnly не дает никакой практической защиты, потому что CSRF предназначен только для защиты от междоменных атак. Если злоумышленник может прочитать куки через JavaScript, он уже находится на том же домене, насколько известно браузеру, так что он может делать все, что захочет. (XSS - это гораздо большая дыра, чем CSRF.)

Основным риском, который следует учитывать, делая CSRF-токены доступными для JavaScript, является XSS - межсайтовый скриптинг . Если ваше приложение уязвимо к XSS, злоумышленник может воспользоваться этим, чтобы полностью обойти защиту CSRF. Поэтому любое решение о передаче CSRF-токенов в JavaScript должно сопровождаться жесткими стратегиями защиты от XSS. Смотрите, например, "Django XSS: примеры и предотвращение" от StackHawk.

Протестируйте процесс получения токена CSRF и куки сессии при входе в систему. Убедитесь, что последующие запросы от React включают токен CSRF в заголовок и куки сессии автоматически (даже если JavaScript не может прочитать куки sessionid из-за флага HttpOnly).

попробуйте это,

npm install http-proxy-middleware

Откройте файл setupProxy.js и добавьте следующий код:

const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
  app.use(
    '/api',
    createProxyMiddleware({
      target: 'http://localhost:8000',
      changeOrigin: true,
    })
  );
};

Другие настройки django кажутся мне нормальными, так что пока не трогайте их.

вариант 2

в файле package.json добавьте этот атрибут на первом уровне отступа.

"proxy":"http://localhost:8000"

погуглите о том, как устанавливаются cookies, вы поймете концепцию безопасного контекста, и почему разное происхождение является проблемой безопасности при установке cookies. объяснение не приводится для краткости. также убедитесь, что используете /api/... и относительно него для дальнейших запросов по той же причине.

Личное мнение: django - хороший человек, react - волшебник. дефолтные настройки react довольно сложны для понимания, и я пропустил сроки, поэтому оставил react для sveltkit.

Добавление простого

CSRF_TRUSTED_ORIGINS = [
    'http://localhost:3000/*',
    'http://localhost:3000/*'

]

Могу помочь!

Вернуться на верх