Spring Boot 部署在反向代理后面时如何配置转发头(forward-headers-strategy)?
【免费下载链接】spring-bootSpring Boot helps you to create Spring-powered, production-grade applications and services with absolute minimum fuss.项目地址: https://gitcode.com/gh_mirrors/sp/spring-boot
当 Spring Boot 应用部署在反向代理、负载均衡器或云平台之后时,应用看到的请求信息(主机名、端口、协议等)可能在中转过程中发生变化——应用可能实际运行在10.10.10.10:8080,但 HTTP 客户端只应该看到example.org。Spring Boot 用server.forward-headers-strategy配置项告诉应用如何读取代理附加在请求上的转发头(forwarded headers),并让应用在创建链接、通过 HTTP 302 响应、JSON 文档或 HTML 页面把链接发送给客户端时自动使用这些信息。本文按“确认代理发送哪组头 → 选择策略 → 按内嵌服务器微调 → 注意信任边界”的顺序给出完整配置路径。
先确认代理发送的是哪一组转发头
中间代理可以用两组 HTTP 头来携带原始请求信息:
- 通用的
"X-Forwarded-*"头,如"X-Forwarded-Host"、"X-Forwarded-Port"、"X-Forwarded-Proto"、"X-Forwarded-For"; "Forwarded"头,由 RFC7239 "Forwarded Headers" 定义。
配置策略的第一步是查清你的代理、负载均衡器或云平台实际发送哪一组。文档指出 RFC7239 虽是标准但业界采用率很低,实践中你大概率需要的是"X-Forwarded-*"。只有确认了头格式,后面的策略选择才有依据。
选择策略:NATIVE 还是 FRAMEWORK
server.forward-headers-strategy有三个取值(见 ServerProperties 中的ForwardHeadersStrategy枚举):
NATIVE:使用内嵌容器自身对转发头的支持;FRAMEWORK:使用 Spring Framework 提供的支持;NONE:忽略X-Forwarded-*头。
关于默认值:当应用运行在一个受支持的云平台上时,server.forward-headers-strategy默认为NATIVE;其他所有情况下默认为NONE。Spring Boot 通过环境变量推断云平台(例如 Kubernetes 环境检查*_SERVICE_HOST和*_SERVICE_PORT变量,AWS ECS 检查AWS_EXECUTION_ENV),并可用spring.main.cloud-platform属性覆盖这一检测。
主路径:NATIVE
如果所选的 web server 支持你需要的头格式,文档给出的建议是把server.forward-headers-strategy设为NATIVE。各服务器的支持情况:
| Server | 支持的转发头 |
|---|---|
| Tomcat | "X-Forwarded-*" |
| Jetty | "X-Forwarded-*"、"Forwarded" |
| Reactor Netty | "X-Forwarded-*"、"Forwarded" |
配置示例:
server: forward-headers-strategy: NATIVE备选:FRAMEWORK
如果容器的原生支持不够,可以使用 Spring Framework 提供的转发头组件:Spring MVC 应用对应ForwardedHeaderFilter,WebFlux 应用对应ForwardedHeaderTransformer。配置方式为把server.forward-headers-strategy设为FRAMEWORK,并用对应栈的属性选择头格式:
- Spring MVC:
spring.mvc.forwarded-headers.header-format - WebFlux:
spring.webflux.forwarded-headers.header-format
header-format的取值对应两种头格式:STANDARD使用 RFC 7239 定义的Forwarded头,X_FORWARDED使用非标准的X-Forwarded-*头(见 WebFluxProperties 中的HeaderFormat枚举)。
server: forward-headers-strategy: FRAMEWORK spring: webflux: forwarded-headers: header-format: STANDARD按内嵌服务器做针对性微调(可选分支)
只有当 NATIVE 的默认行为与你的代理配置不完全匹配时,才需要进入这一节。
Tomcat
使用 Tomcat 时,可以额外配置用于携带转发信息的头名称:
server: tomcat: remoteip: remote-ip-header: "x-your-remote-ip-header" protocol-header: "x-your-protocol-header"Tomcat 还用一个正则表达式匹配应当被信任的内部代理。可以往application.properties中加一条来自server.tomcat.remoteip.internal-proxies的自定义项(默认值见附录属性索引):
server: tomcat: remoteip: internal-proxies: "192\\.168\\.\\d{1,3}\\.\\d{1,3}"注意:把internal-proxies设为空可以信任所有代理,但文档明确提示不要在生产环境这样做。
一条与跳转直接相关的提示:如果你使用 Tomcat、在代理端终结 SSL,并且已经把server.tomcat.servlet.use-relative-redirects设为false,那么还应把server.tomcat.servlet.redirect-context-root也设为false,这样才能让X-Forwarded-Proto头在执行任何重定向前被正确采用;而当使用相对重定向(Tomcat 的默认行为)时,context root 重定向本身不携带 scheme,也就没有可供该头纠正的内容。
如果需要完全接管 TomcatRemoteIpValve的配置,可以把自动配置关掉(设server.forward-headers-strategy=NONE),再通过WebServerFactoryCustomizerbean 添加一个新的 valve 实例。
Jetty
Jetty 默认使用"X-Forwarded-*"格式,可以切换为标准 RFC 变体:
server: jetty: forwarded-headers: header-format: "standard"需要更多选项时,把server.forward-headers-strategy设为NONE,直接使用 Jetty 的ForwardedRequestCustomizer修改 HTTP 配置。
Reactor Netty
Reactor Netty 同样默认使用"X-Forwarded-*"格式,可切换为标准 RFC 变体:
server: netty: forwarded-headers: header-format: "standard"需要更多选项时,把server.forward-headers-strategy设为NONE,直接使用reactor.netty.http.server.HttpServer的 forwarded header 支持。
信任边界:只在可信代理后面启用
文档在云部署的安全注意事项中给出的原则是:支持转发头应当仅在应用从受信任的 HTTP 代理接收流量、并且只能从受信任网络直接访问时才启用。在云平台运行时,转发头会被自动启用,这基于一个假设:平台会保证单个应用实例只能从受信任网络直接访问。如果你的特定平台不满足这个条件,把server.forward-headers-strategy设为none:
server: forward-headers-strategy: none如何验证配置生效
文档描述该功能生效后的行为是:应用自动使用转发头携带的信息来创建链接,并在 HTTP 302 响应、JSON 文档或 HTML 页面中把这些链接发送给客户端。因此验证方式是:通过代理的外部地址访问应用,检查返回给客户端的链接(包括重定向目标)使用的是外部主机名和协议(例如https://example.org),而不是应用内部实际监听的地址和端口。若你的代理终结了 SSL,重点检查 302 重定向目标是否采用了X-Forwarded-Proto提供的协议;对于 Tomcat,这依赖前面提到的redirect-context-root相关设置。
本文内容整理自仓库内的 Embedded Web Servers(how-to) 和 Deploying to the Cloud(how-to)。
【免费下载链接】spring-bootSpring Boot helps you to create Spring-powered, production-grade applications and services with absolute minimum fuss.项目地址: https://gitcode.com/gh_mirrors/sp/spring-boot
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考