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/*'
]
Могу помочь!