我创建了这个 Django 和 React 项目(https://github.com/axilaris/docker-django-react-celery-redis),并且我在使用 SessionAuthentication 访问 API 时遇到困难。您可以轻松地测试并剥离我的代码:
我在访问 /api/user 时不断遇到访问问题(您可以通过注册、登录进行测试)
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);
});
}, []);
这是我的网络日志:https://gist.github.com/axilaris/f5076f8a1e009d77df78de562259427e
/api/login 确实提供了 csrftoken 和 sessionid cookie。但是这个cookie没有在/api/user中使用
为什么每当我登录并在浏览器上重新加载回本地主机后,它就会禁止 /api/user 并返回到登录页面。我觉得 CORS 设置正确,并且后端和前端的凭据都设置为 true。
来自 ChatGPT 的更新(询问如何使其与 HttpOnly 一起工作):
If you can't access the session cookie from the client-side, it's probably because the cookie has the HttpOnly flag set. This is a security feature that prevents JavaScript from accessing the cookie, helping mitigate cross-site scripting attacks.
你有:
Client (React) --> [HTTP Request with CSRF Token] --> Django Backend
/\
|
+--- [Session Authentication & CSRF Validation]
SessionAuthentication
正常工作,请确保正确设置 Django 的会话 cookie (sessionid
) 和 CSRF 令牌 cookie (csrftoken
) 并将其发送到客户端。通常应在 HttpOnly
cookie 上设置 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 cookie 配置:
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 cookie。更好的方法是保留 CSRF 令牌 HttpOnly
,并从旨在显式返回 CSRF 令牌的单独 API 端点获取它,或者将 CSRF 令牌包含在页面正文中并让 JavaScript 从那里读取它。
django/django
PR 7700 和 commit c27104a
将 CSRF cookie 指定为
并不能提供任何实际保护,因为 CSRF 仅用于防止跨域攻击。如果攻击者可以通过 JavaScript 读取 cookie,那么就浏览器所知,他们已经位于同一个域中,因此他们无论如何都可以做任何他们喜欢做的事情。 (XSS 是一个比 CSRF 大得多的漏洞。)HttpOnly
使 JavaScript 可以访问 CSRF 令牌时要考虑的主要风险是 XSS——跨站点脚本 。如果您的应用程序容易受到 XSS 攻击,攻击者可以利用此漏洞完全绕过 CSRF 保护。因此,任何向 JavaScript 公开 CSRF 令牌的决定都应该伴随严格的 XSS 缓解策略。例如,请参阅 StackHawk 中的“Django XSS:示例和预防”。
测试登录时获取CSRF token和session cookie的流程。验证来自 React 的后续请求是否自动在标头和会话 cookie 中包含 CSRF 令牌(即使 JavaScript 由于
sessionid
标志而无法读取 HttpOnly
cookie)。