
Flask 生产部署使用 ProxyFix 中间件让应用正确识别反向代理后的真实客户端【免费下载链接】flaskThe Python micro framework for building web applications.项目地址: https://gitcode.com/gh_mirrors/fl/flask在反向代理或托管平台后运行 Flask 应用时WSGI 服务看到的请求来源是代理服务器而非真实客户端导致 IP、协议、主机名等信息失真。本文基于 Flask 官方文档 proxy_fix.rst 展开讲清X-Forwarded-*头部如何传递真实值、如何用 Werkzeug 的ProxyFix中间件接管这些头部以及为什么必须按代理层数精确配置信任参数——配置错误会带来真实的安全风险。读完后你可以独立完成nginx 反代 Gunicorn Flask这一典型生产链路中代理信息的正确配置。为什么需要 ProxyFix反向代理改变了请求的来源生产部署的典型架构是客户端 → HTTP 服务器如 nginx负责 TLS 终止等→ WSGI 服务器如 Gunicorn→ Flask 应用。相关背景可参阅 生产部署总览 与 nginx 配置页。在这种架构下代理会拦截并转发所有外部请求到本地的 WSGI 服务器。从 WSGI 服务器和 Flask 应用的视角看请求变成了来自 HTTP 服务器所在的本机地址而不是来自远端客户端指向外部服务器地址。也就是说以下常用信息全部失真request.remote_addr变成代理的地址如127.0.0.1而不是客户端 IPrequest.scheme代理终结 TLS 后WSGI 服务器收到的是http即使原始请求是httpsrequest.host代理转发的Host头可能与客户端实际访问的主机名不同。这些信息会影响日志记录、基于 IP 的限流/封禁、url_for(..., _externalTrue)生成外链等场景。X-Forwarded 头部代理如何把真实值传下去HTTP 服务器应当在转发请求时设置X-Forwarded-系列头部把真实值传递给应用。Flask 文档中的 nginx 配置示例 就是完整的配套写法server { listen 80; server_name _; location / { proxy_pass http://127.0.0.1:8000/; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Prefix /; } }四个头部分别携带的信息头部携带的真实值对应ProxyFix参数X-Forwarded-For客户端 IP经过多级代理时为链路x_forX-Forwarded-Proto客户端与代理之间的原始协议http/httpsx_protoX-Forwarded-Host客户端实际请求的主机名x_hostX-Forwarded-Prefix应用被挂载的前缀路径x_prefixApache httpd 的部署文档 同样要求代理设置X-Forwarded头部后由应用侧接管。但需要注意并非所有代理都会设置全部头部不同代理产品对这几个头部的支持并不一致配置时要按你实际使用的代理来核对。应用 ProxyFix 中间件让 Flask 信任这些头部代理设置头部只是传话Flask 本身默认不会信任这些头部。要让应用使用这些值需要用 Werkzeug 提供的ProxyFix中间件包裹应用from werkzeug.middleware.proxy_fix import ProxyFix app.wsgi_app ProxyFix( app.wsgi_app, x_for1, x_proto1, x_host1, x_prefix1 )官方文档给出的这四个参数x_for1, x_proto1, x_host1, x_prefix1表示每种头部都只有1 级代理在设置因此只信任该头部链中最靠近代理一侧的值。参数值应与实际架构中设置了该头部的代理层数一致——例如中间还有一层 CDN 或负载均衡器也在追加X-Forwarded-For那么x_for就应相应调大否则解析出的客户端 IP 会停留在中间层。为什么必须按代理层数配置这是安全问题proxy_fix 文档 反复强调了三点每一条都直接关系到安全只在应用真的位于代理后面时才启用此中间件。直接暴露的应用如果套上ProxyFix等于向所有访问者开放了伪造头部的通道。必须按代理链路上实际设置头部的代理数量配置参数。信任数量配置偏大会让攻击者有机会通过头部注入欺骗应用配置偏小则应用仍会读到中间层的值信息失真问题没有解决。传入的头部可以被伪造。因为X-Forwarded-*就是普通 HTTP 头部任何人都能从外部手动携带它们发请求。ProxyFix的信任层数参数就是告诉中间件头部链中只有最内侧的 N 个值是代理写入的、可信的。文档明确警告如果这个配置错了会造成安全问题a security issue。为什么包装app.wsgi_app而不是app从 Flask 应用源码 看Flask.wsgi_app方法文档字符串直接给出了推荐写法# 不推荐丢失了对 app 对象的引用 app MyMiddleware(app) # 推荐包装 wsgi_app app.wsgi_app MyMiddleware(app.wsgi_app)原因是 quickstart 文档 中的解释包装app.wsgi_app而不是app意味着app变量仍然指向你的 Flask 应用对象本身而不是中间件对象因此后续可以继续直接在app上调用route、add_url_rule等方法。从 lifecycle 文档 的中间件小节也可以看到整体调用链WSGI 服务器或最外层中间件调用的是wsgi_app而Flask.__call__内部也正是转发到self.wsgi_app(environ, start_response)见 app.py。ProxyFix属于典型的请求改写中间件——它让经过代理的请求看起来像直接来自客户端因此它作用于environ解析为Request对象之前位置必须在 Flask 应用处理逻辑的外层。实际项目中这类包装一般放在应用工厂或入口文件里集中完成例如使用 app factory 模式时在create_app()返回应用前执行app.wsgi_app ProxyFix(app.wsgi_app, ...)。与 Host 头校验的配合Web 安全文档 在Host Header Validation一节指出Host头可能被客户端与代理之间的中间环节修改并明确指向本页——告诉你的应用哪些代理值可信。因此一个完整的生产安全配置通常是两者配合部署时设置TRUSTED_HOSTS限制Host头的合法取值范围用ProxyFix配置代理信任参数让应用从代理传入的X-Forwarded-Host中恢复真实主机名。只设其一都会留下缺口只限制而不信任代理代理改写后的主机名可能不在白名单内只信任代理而不设限制直连场景下仍可被伪造Host头。适用前提与限制小结仅当应用确实位于反向代理或托管平台之后时才应用ProxyFix并核对实际代理链路上每一级设置哪些头部托管平台如 部署总览 中列出的各类平台大多自带一层或更多层代理通常都需要本方案层数需按平台实际拓扑确定ProxyFix来自 Werkzeugwerkzeug.middleware.proxy_fix随 Flask 依赖提供其行为细节如各级头部的解析规则以 Werkzeug 文档为准参数错误的代价是安全的而非仅仅是不生效信任层数过大可能被伪造头部欺骗过小则取不到真实客户端信息。核心结论可以浓缩为官方文档原话记住只在代理后面才应用这个中间件并设置正确设置了每个头部的代理数量——配错它就是安全问题。【免费下载链接】flaskThe Python micro framework for building web applications.项目地址: https://gitcode.com/gh_mirrors/fl/flask创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考