proxy_hide_header X-Runtime 必须置于 proxy_pass 之后才生效,每行仅支持一个头字段,且仅在当前 location 块内有效;它会屏蔽所有同名响应头,而 X-Runtime 因暴露后端技术栈和耗时信息构成安全风险。

proxy_hide_header X-Runtime 必须写在 proxy_pass 之后
很多人配了 proxy_hide_header X-Runtime 却没生效,根本原因是它被放在 proxy_pass 前面。Nginx 的处理逻辑是:先转发请求、拿到响应后,再按顺序执行后续指令;如果 proxy_hide_header 在 proxy_pass 之前,它根本没机会作用于上游响应头。
正确写法必须是:
location /api/ {
proxy_pass http://backend;
proxy_hide_header X-Runtime;
}
-
proxy_hide_header每行只能写一个字段,不支持X-Runtime, X-Powered-By这种逗号分隔写法 - 它只对当前
location生效,父块(如http或server)里写的不会自动继承 - 若后端多次设置
X-Runtime(比如中间件 + 应用层各设一次),该指令会把所有同名头一并屏蔽
为什么 X-Runtime 是高风险头?
X-Runtime 常见于 Rails、Spring Boot、某些 Java 中间件或自定义监控埋点中,值类似 0.123456(秒级耗时)。表面看只是性能指标,但它暴露了真实服务端行为:
- 间接确认后端是 Ruby on Rails(Rails 默认注入)或某类 Java 容器(如 Tomcat + 自定义 filter)
- 结合其他头(如
X-Powered-By)可交叉验证技术栈版本 - 在错误页或调试接口中,
X-Runtime可能和堆栈、SQL 查询一起返回,成为攻击链路的一环
它不像 Server 那样显眼,但自动化扫描工具(如 Nikto、nuclei)会主动检查这类“非标准但高频”的头,属于低垂果实型泄露。
curl -I 验证时容易忽略的两个盲区
配置完别急着 reload,用 curl -I 测之前,先确认两件事:
- 测试路径是否命中你写的
location:比如你只在location /api/里写了proxy_hide_header X-Runtime,但用curl -I https://example.com/health测,那肯定看不到效果 - 检查错误响应(4xx/5xx)是否也清理干净:
X-Runtime往往在 500 页面里更活跃(比如 Spring Boot 的 Whitelabel Error Page),而默认错误页可能绕过你的location规则,直接走 Nginx 内置错误流
建议实测命令组合:
curl -I https://your-domain.com/api/v1/users curl -I -X POST https://your-domain.com/api/v1/login # 看 POST 是否也触发后端耗时头 curl -I https://your-domain.com/actuator/health # 若暴露了 Spring Boot Endpoint
proxy_hide_header 对 X-Runtime 无效?先排除这三点
如果确认位置、路径、reload 都没问题,但 X-Runtime 还在响应头里,大概率是以下情况之一:
- 后端没返回它,而是前端 JS 动态加的(比如 Axios 拦截器、Vue 插件)——这不是 Nginx 能管的范围
- 你用的是 FastCGI(如 PHP-FPM)而非 HTTP 代理,该场景要用
fastcgi_hide_header X-Runtime,不是proxy_hide_header -
X-Runtime其实是响应体里的内容(比如 JSON 字段"runtime": "0.123"),proxy_hide_header只处理响应头,对响应体完全无感
真正难缠的不是配置本身,而是你以为它藏在头里,其实它混在 HTML 或 JSON 里——这种泄露,Nginx 束手无策,得靠后端关掉调试模式或过滤响应体。











