django - Django CSRF“Referer Malformed”……但事实并非如此
问题描述
我正在尝试测试在开发模式下运行良好的 Django 设置的部署配置。
我通过ssl_preread
负载均衡器上的 Nginx 模块进行基于名称的路由,并且 SSL 终止于服务器本身上的另一个 Nginx 实例,其中请求通过套接字代理到 uwsgi。
server {
server_name dev.domain.net;
listen 80 proxy_protocol;
listen [::]:80 proxy_protocol;
location / {
return 301 https://$host$request_uri;
}
}
server {
server_name dev.domain.net;
listen 443 ssl;
listen [::]:443 ssl;
location / {
include uwsgi_params;
uwsgi_pass unix:/run/uwsgi/website.sock;
}
location /favicon.ico {
access_log off; log_not_found off;
}
}
我将 uwsgi 设置为 log%(host)
并且%(referer)
,它们在日志中匹配。
在我的 uwsgi_params 中,我正在传递$host
,$referer
因为我使用的是基于名称的路由,所以我选择了$server_name
触发 Nginx 响应的变量......
uwsgi_param HTTP_REFERER $server_name;
uwsgi_param HTTP_HOST $host;
向这些添加(或删除)协议和端口没有任何区别。可以预见地将它们带走会产生 DjangoALLOWED_HOSTS
调试错误。
我已经确认我的ALLOWED_HOSTS
包含$host
. 我尝试添加CSRF_TRUSTED_ORIGINS
相同的$host
变量。我试过设置CSRF_COOKIE_DOMAIN
相同的$host
变量。根据文档建议,我已CSRF_COOKIE_SECURE
设置为 True。
无论使用上述设置的哪种组合,我都会得到:
Referer checking failed - Referer is malformed.
在所有 POST 请求上。
解决方案
简短的回答:不要使用 uwsgi unix 套接字,而是使用http-socket
代理请求并将代理请求通过未加密的 http 发送到 localhost(在 uwsgi ini 文件中):
http-socket = 127.0.0.1:8001
在 nginx 中,去掉 uwsgi 代理参数,只需proxy_pass
启用proxy_protocol
标头即可:
server {
server_name dev.domain.net;
listen 443 ssl proxy_protocol;
listen [::]:443 ssl proxy_protocol;
location / {
proxy_pass http://127.0.0.1:8001;
}
location /favicon.ico {
access_log off; log_not_found off;
}
}
此时,您可以启用 Django 文档中所有推荐的部署设置,明确声明您的ALLOWED_HOSTS
并且一切正常。
这是一系列非常愚蠢的圈套,没有明显的正确答案,特别是考虑到引用者是很容易伪造的客户端标头。
更好的答案是 Django 需要在其 CSRF 机制中摆脱客户端引用检查,这是毫无意义的,没有意义......
推荐阅读
- apache - ModSecurity:使用 woocomerce rest api 使用代码 403(阶段 1)拒绝访问
- docker - docker无效的参考格式
- spring - 如何使用 @RequestMapping 将自定义 HTTP 方法/动词添加到 Spring-MVC
- r - 如何根据两个重复的行平均行?
- selenium - 在用于页面对象模型的 testNG 中的 @Test 注释之前,最好使用哪个注释?
- c++ - c++ 上的函数和结构的问题
- c# - dotnetnuke 中的连接池问题。在从池中获取连接之前经过的超时时间
- python - 使用 apply 方法修改 DataFrame
- python - 如何将此 CSV 转换为 Json?
- javascript - 计算方法在vue js中更改复选框值时不更新