我有一个使用 Spring Security 保护的 Spring MVC 应用程序。大多数应用程序使用简单的 HTTP 来节省资源,但一小部分处理更多 secret 信息并需要 HTTPS channel 。
从 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
header (*),但是在 Spring Security HttpServletRequest.isSecure()
用于确定提供的 channel 安全(摘自 SecureChannelProcessor
javadoc)。
我如何告诉 Spring Security X-Forwarded-Proto: https
header 足以满足安全请求?
我知道我可以报告有关代理配置的部分,但代理管理员真的不喜欢该解决方案,因为代理背后有许多应用程序,配置可能会增长到无法管理的状态。
我目前正在使用带有 XML 配置的 Spring Security 3.2,但我已准备好接受基于 Java 配置和/或更新版本的答案。
(*) 当然,代理会删除传入请求中出现的 header ,因此应用程序可以对此充满信心。
最佳答案
类似于 NeilMcGuigan 的回答,表明解决方案是 servlet 容器端。
Tomcat 甚至更好。有一个阀 专门用于屏蔽 反向代理的副作用。从 Tomcat 文档中提取 Remote IP Valve :
此阀门的另一个功能是通过请求 header (例如“X-Forwarded -Proto").
阀门配置示例:
<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" />
这样应用程序本身没有其他配置,如果请求包含 的 header 字段,则对
.Request.isSecure()
的调用将返回 true X-Forwarded-Proto=https
我想到了另外两种可能性,但最终还是更喜欢那个:
- 使用在 Spring Security
ChannelProcessingFilter
之前激活的过滤器,用HttpServletRequestWrapper
覆盖isSecure()
来包装请求以处理X -Forwarded-Proto
header - 需要编写和测试过滤器和包装器 - 使用 Spring
BeanPostProcessor
寻找ChannelProcessingFilter
并手动注入(inject)能够考虑X-Forwarded-Proto 的
header - 级别真的太低了ChannelDecisionManager
关于java - 在反向代理后面需要 HTTPS 和 Spring Security,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30076551/