繁体   English   中英

在反向代理后面需要带有 Spring Security 的 HTTPS

[英]Require HTTPS with Spring Security behind a reverse proxy

我有一个使用 Spring Security 保护的 Spring MVC 应用程序。 大多数应用程序使用简单的 HTTP 来节省资源,但一小部分处理更机密的信息并需要 HTTPS 通道。

security-config.xml提取:

<sec:http authentication-manager-ref="authenticationManager" ... >
    ...
    <sec:intercept-url pattern="/sec/**" requires-channel="https"/>
    <sec:intercept-url pattern="/**" requires-channel="http"/>
</sec:http>

一切正常,直到我们决定将其迁移到主服务器,应用服务器在反向代理之后运行。 现在 HTTPS 由反向代理处理,应用程序服务器只能看到 HTTP 请求,并且不允许访问/sec/**层次结构。

经过一番研究,我发现代理添加了X-Forwarded-Proto: https标头(*) ,但在 Spring Security 中HttpServletRequest.isSecure()用于确定提供的通道安全性(摘自SecureChannelProcessor javadoc)。

我如何告诉 Spring Security X-Forwarded-Proto: https标头足以满足安全请求?

我知道我可以报告关于代理配置的那部分,但是代理管理员真的不喜欢这个解决方案,因为代理背后有很多应用程序,并且配置可能会增长到不可管理的状态。

我目前使用带有 XML 配置的 Spring Security 3.2,但我准备接受基于 Java 配置和/或更新版本的答案。

(*)当然,如果传入请求中存在标头,代理会删除标头,因此应用程序可以对其有信心。

对 NeilMcGuigan 的回答的一种跟进,表明解决方案是 servlet 容器端。

Tomcat 甚至更好。 有一个阀门专门用于掩盖反向代理的副作用。 摘自远程 IP Valve 的Tomcat 文档:

此阀的另一个功能是用代理或负载均衡器通过请求标头(例如“X-Forwarded-Proto”)呈现的方案替换明显的方案(http/https)、服务器端口和 request.secure。

阀门配置示例:

<Valve className="org.apache.catalina.valves.RemoteIpValve"
    internalProxies="192\.168\.0\.10|192\.168\.0\.11"
    remoteIpHeader="x-forwarded-for" proxiesHeader="x-forwarded-by"
    protocolHeader="x-forwarded-proto" />

这样,在没有应用程序本身的其他配置的情况下,如果请求包含X-Forwarded-Proto=https的标头字段,则对Request.isSecure()的调用将返回 true。

我曾想过另外两种可能性,但绝对更喜欢那个:

  • 在 Spring Security ChannelProcessingFilter之前使用激活的过滤器,用覆盖isSecure()HttpServletRequestWrapper包装请求以处理X-Forwarded-Proto标头 - 需要编写和测试过滤器和包装器
  • 使用 Spring BeanPostProcessor查找ChannelProcessingFilter并手动注入一个ChannelDecisionManager能够考虑X-Forwarded-Proto标头 - 真的太低级了

Spring Boot 使它变得非常简单(至少对于嵌入式 Tomcat)。

1. 将以下行添加到您的 application.properties:

server.forward-headers-strategy=native
server.tomcat.remote-ip-header=x-forwarded-for
server.tomcat.protocol-header=x-forwarded-proto

2. 使用您的HttpSecurity配置执行以下技巧。

// final HttpSecurity http = ...
// Probably it will be in your `WebSecurityConfigurerAdapter.configure()`

http.requiresChannel()
            .anyRequest().requiresSecure()

来源是 Spring Boot 参考指南

84.3 在代理服务器后面运行时启用 HTTPS

另请查看下面的答案以了解与 Spring Boot 2.2 相关细节

如果您的站点是 HTTPS 并且您在另一个处理 TLS 终止的系统后面运行 Apache Tomcat,您可以告诉 Tomcat“假装”它正在处理 TLS 终止。

这使得request.isSecure()返回true

为此,您需要将secure="true"添加到server.xml的连接器配置中。

https://tomcat.apache.org/tomcat-7.0-doc/config/http.html

另请参阅scheme属性。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM