直接用 $request_uri 动态改写 host 头无法解决越权 403 问题,因 host 不参与鉴权;真正有效的是路径级拦截(如 if $request_uri 匹配敏感路径 return 403)和 host 头严格校验(如限定合法域名并 proxy_set_header host 固定值)。

直接用 $request_uri 动态改写 Host 头部并不能解决越权访问的 403 问题——它本身不参与权限控制,也不影响后端鉴权逻辑。真正起作用的是对请求路径的识别与拦截,Host 头只是用于路由或校验,不能“绕过”安全限制。
关键点:$request_uri 是匹配依据,不是改写工具
$request_uri 是只读变量,记录客户端原始请求路径(含 query string),比如 /admin/api/users?limit=10。它常用于 if 判断或 map 映射,但不能用来“动态设置” Host 头——Host 头由 proxy_set_header Host ... 显式指定,且应保持业务语义一致(如后端依赖 Host 做租户识别或 CORS 校验)。
- 强行用
$request_uri拼接 Host(如proxy_set_header Host $request_uri)会导致 Host 变成路径字符串,后端解析失败,多数服务直接拒收 - Host 头伪造本身是攻击面,Nginx 正确做法是严格校验 Host,而非动态生成
真正解决 403 越权瓶颈的路径级控制
403 通常源于后端拒绝了非法路径(如 /config、/sql),而非 Host 不匹配。应在反向代理层做前置过滤:
- 用
if ($request_uri ~* "^/(admin|config|\.git|phpmyadmin|\.env)") { return 403; }在 location 内拦截敏感路径 - 配合白名单机制:只允许
/api/、/static/等已知安全前缀通过 - 避免在
server块顶层写if,应放在具体location下,防止规则误伤
Host 头安全加固才是配合手段
确保 Host 头可信,才能让后端信任转发来源:
- 显式限定合法域名:
if ($host !~ ^(hr\.internal|docs\.internal|git\.internal)$) { return 403; } - 禁用空 Host 或 IP 直连:
if ($host = "") { return 400; } - 转发时固定可信 Host:
proxy_set_header Host hr.internal;(而非$host),切断前端可控输入链路
路径重写需谨慎,优先走 proxy_pass 规则
若业务确实需要路径映射(如把 /hr/ 转为后端 /),应使用 proxy_pass 的路径截断逻辑,而非改写 Host:
-
location /hr/ { proxy_pass http://192.168.10.10:8080/; }→ 请求/hr/user转发为http://.../user(自动去掉/hr/) -
location /api/ { proxy_pass http://backend/api/; }→ 保持路径结构,仅变更上游根路径 - 避免用
rewrite配合proxy_pass,易引发循环或丢失 query string











