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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30076551/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 16:24:50  来源:igfitidea点击:

Require HTTPS with Spring Security behind a reverse proxy

javahttpsspring-securityreverse-proxy

提问by Serge Ballesta

I have a Spring MVC application secured with Spring Security. The majority of the application uses simple HTTP to save resources, but a small part processes more confidential information and requires an HTTPS channel.

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

Extract from the security-config.xml:

摘自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>

All worked fine until we decided to migrate it to the main server, where the application servers run behind reverse proxies. And as now HTTPS is processed by the reverse proxies the application server only sees HTTP requests, and disallows access to the /sec/**hierarchy.

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

After some research, I found that the proxies add a X-Forwarded-Proto: httpsheader (*), but in Spring Security HttpServletRequest.isSecure()is used to determine the channel security offered(extract from SecureChannelProcessorjavadoc).

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

How can I tell Spring Security that a X-Forwarded-Proto: httpsheader is enough for a secure request?

我如何告诉 Spring Security 一个X-Forwarded-Proto: https标头对于安全请求来说已经足够了?

I know I could report that part on proxies configuration, but the proxies administrator really does not like that solution, because there are many application behind the proxies and the configuration could grow to a non manageable state.

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

I an currently using Spring Security 3.2 with XML config, but I'm ready to accept answers based on Java config and/or more recent version.

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

(*)Of course, the proxies remove the header if it was present in incoming request, so the application can be confident in it.

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

采纳答案by Neil McGuigan

If your site is HTTPS and you're running Apache Tomcat behind another system that's handling TLS termination, you can tell Tomcat to "pretend" that it's handling the TLS termination.

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

This makes request.isSecure()return true;

这使得request.isSecure()return true;

To do so, you need to add secure="true"to your Connector config in server.xml.

为此,您需要secure="true"server.xml.

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

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

See also the schemeattribute.

另请参见scheme属性。

回答by Serge Ballesta

Kind of a followup to NeilMcGuigan's answer that showed that the solution was servlet container side.

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

Tomcat is even better. There is a valvededicated to maskingthe side effects of a reverse proxy. Extract from Tomcat documentation for Remote IP Valve:

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

Another feature of this valve is to replace the apparent scheme (http/https), server port and request.secure with the scheme presented by a proxy or a load balancer via a request header (e.g. "X-Forwarded-Proto").

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

Example of the valve configuration :

阀门配置示例:

<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" />

That way with no other configuration of the application itself, the call to Request.isSecure()will return true if the request contains a header field of X-Forwarded-Proto=https.

这样,在没有应用程序本身的其他配置的情况下Request.isSecure()如果请求包含X-Forwarded-Proto=https.

I had thought of two other possibilities, but definitively prefere that one :

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

  • use a filter active before Spring Security ChannelProcessingFilterto wrap the request with a HttpServletRequestWrapperoverriding isSecure()to process a X-Forwarded-Protoheader - need writing and testing the filter and the wrapper
  • use a Spring BeanPostProcessorto look for a ChannelProcessingFilterand manually inject a ChannelDecisionManagerable to consider the X-Forwarded-Protoheader - really too low level
  • 使用过滤器活跃的Spring Security之前ChannelProcessingFilter包裹的请求,以此HttpServletRequestWrapper覆盖isSecure()到处理X-Forwarded-Proto头-需要编写和测试过滤器和包装
  • 使用 SpringBeanPostProcessor寻找一个ChannelProcessingFilter并手动注入一个ChannelDecisionManager能够考虑X-Forwarded-Proto标题的 - 真的太低级了

回答by Roman Nikitchenko

Spring Boot makes it dead simple (at least with embedded Tomcat).

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

1. Add the following lines to your application.properties:

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

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

2. Do the following trick with your HttpSecurityconfiguration.

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

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

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


Source is Spring Boot reference guide

来源是 Spring Boot 参考指南

84.3 Enable HTTPS When Running behind a Proxy Server

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

Please also check the answer below for a specifics related to Spring Boot 2.2

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