使用Spring Security进行HTTPS登录后重定向到HTTP页面。

53

我有一个使用Spring Security保护的Spring Web应用程序,运行在EC2上。在EC2实例前面有一个Elastic Load Balancer,其中包含一个SSL证书(https终止于负载均衡器,即端口443->端口80),因此从Tomcat的角度来看,入站请求是HTTP。

我的登录表单提交到https,但是随后的重定向转到http(成功或失败)。身份验证成功,并且我可以返回https并保持登录状态。

我的登录配置如下:

<security:form-login
    default-target-url="/home"
    login-page="/"
    login-processing-url="/processlogin"
    authentication-failure-url="/?login_error=1"/>

我需要更改什么才能使default-target-url和authentication-failure-url跳转到https?

  • Tomcat 6
  • Spring Security 3.0.x

我已经设置了一个Apache重写,但仍然好奇是否有一种方法可以在Spring Security配置中完成。 - Thody
通常情况下,这是在负载均衡器上完成的,配置称为URL重写。这样,负载均衡器可以确保重定向保持在HTTPS上。 - Ritesh
10个回答

31

您的Spring配置应该对使用的协议保持不可知。如果您使用类似于“requires-channel”的东西,您迟早会遇到问题,尤其是如果您想将相同的应用程序部署到没有https的开发环境中。

相反,考虑正确配置您的Tomcat。您可以使用RemoteIpValve来实现这一点。根据负载均衡器发送的头信息,您的server.xml配置需要包含类似以下内容的设置:

<Valve
   className="org.apache.catalina.valves.RemoteIpValve"
   internalProxies=".*"
   protocolHeader="X-Forwarded-Proto"
   httpsServerPort="443"
   />

如果您使用的不是443端口,请更改httpsServerPort,Spring将根据ServletRequest确定绝对重定向地址:

当protocolHeader指示https协议时,httpsServerPort是由ServletRequest.getServerPort()返回的端口号。


实际加载Servlet请求中的http方案的代码可以在以下链接找到:https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/web/util/UrlUtils.html从这里可以发现,Spring实际上是从Servlet请求中收集http方案的。因此,@marcelj的解决方案是完美的答案! - Imtiaz Shakil Siddique

15
如果这是一个 Spring Boot 应用程序(我目前使用的是 2.0.0 版本),在 application.properties 文件中添加以下配置应该就足够了:
server.tomcat.protocol-header=x-forwarded-proto

我在使用 AWS 的负载均衡器时,这个方法对我有效。

对于 Spring Boot < 2.0.0,它也应该有效(未经测试)。


这个问题让我疯了,这个建议完美解决了它。谢谢! - John A
3
谢谢!我还需要添加 server.use-forward-headers=true。参见 https://docs.spring.io/spring-boot/docs/current/reference/html/howto-embedded-web-servers.html#howto-use-tomcat-behind-a-proxy-server - Jeff Sheets

5

我在谷歌Kubernetes后面使用Spring Boot时也遇到了同样的问题。在application.properties中添加以下两行代码就解决了问题

server.tomcat.remote-ip-header=x-forwarded-for
server.tomcat.protocol-header=x-forwarded-proto

来源:https://docs.spring.io/spring-boot/docs/current/reference/html/howto-security.html#howto-enable-https

本文介绍如何在Spring Boot应用程序中启用HTTPS。要启用HTTPS,您需要生成自签名证书或购买可信证书并将其配置到您的应用程序中。使用自签名证书只适用于开发或测试环境,并不适用于生产环境。一旦您有了证书,您需要配置应用程序以使用HTTPS协议。配置过程包括添加依赖项和更改应用程序属性文件或YAML文件中的设置。完成这些步骤后,您的应用程序会通过HTTPS协议进行通信,从而提供更安全的数据传输。

3
解决方案有两个部分:
(1)application.yml
server:
  use-forward-headers: true

(2)在服务器中/etc/apache2/sites-enabled/oow.com-le-ssl.conf文件中。

RequestHeader set X-Forwarded-Proto https
RequestHeader set X-Forwarded-Port 443

(2.1) 并启用了Apache模块

sudo a2enmod headers

借助这里这里,将它们结合起来。


2
server.use-forward-headers=true已经弃用。请改用server.forward-headers-strategy=native,并且不要将其设置为framework,除非您信任您的反向代理 ;-). - jumping_monkey
我们在Chrome上遇到了错误“您即将提交的信息不安全”。为了解决这个问题,我们在application.yml中添加了server.forward-headers-strategy: native,并在我们的docker compose中向traefik添加了以下行“traefik.frontend.headers.customResponseHeaders=X-Forwarded-Proto:https||X-Forwarded-Port:443” - vilvic

2

我通过添加以下配置来使其正常工作:

<http auto-config="true" use-expressions="true" entry-point-ref="authenticationEntryPoint" >
    <form-login login-page="/login.jsf" authentication-failure-url="/login.jsf?login_error=t" always-use-default-target="true" default-target-url="xxxxx" />
    <logout logout-url="/logout" logout-success-url="/logoutSuccess.jsf" />
    ...
</http>

需要添加always-use-default-target="true"default-target-url="https://...."。这不是理想的方式,因为您需要在配置中硬编码URL。


0
在我的情况下,我必须删除属性server.use-forward-headers=true
这是我的设置:
Digital Ocean负载均衡器 --> Kubernetes集群使用Ingress --> Spring Boot应用程序。

0

我尝试了上述所有方法来将我的k8应用程序转换为Spring Boot应用程序,但问题在于k8是安全的,并且SSL由位于Ingress前面的SSL加速器处理。该应用程序仅接收HTTP请求,而Spring Security也转发到HTTP,但从未找到。对我有效的解决方案是:

nginx.ingress.kubernetes.io/proxy-redirect-from: http://$http_host/ nginx.ingress.kubernetes.io/proxy-redirect-to: https://$http_host/$namespace/helloworld-service/


0
请在web.xml中使用以下代码行。
<security-constraint>
  <web-resource-collection>
    <web-resource-name>Login and Restricted Space URLs</web-resource-name>
    <url-pattern>/j_security_check</url-pattern>
    <url-pattern>/loginpage.rose</url-pattern>
  </web-resource-collection>
  <user-data-constraint>
    <transport-guarantee>CONFIDENTIAL</transport-guarantee>
  </user-data-constraint>
</security-constraint>

它强制使用HTTPS。


0

我也遇到了完全相同的问题,目前我使用 AJP 协议将代理服务器上的请求重定向到 Tomcat 服务器,直到找到适当的解决方案。 下面是我的 Apache 配置:

ProxyPass /myproject ajp://localhost:8009/myproject
ProxyPassReverse /myproject ajp://localhost:8009/myproject

0

我在所有的拦截URL上设置了requires-channel="any"。这使得它仍然可以在我不使用SSL的开发环境中工作。

<intercept-url pattern="/createUser" access="permitAll" requires-channel="any"/>
<intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')" requires-channel="any"/>
<intercept-url pattern="/**" access="isAuthenticated()" requires-channel="any"/>

接下来,创建一个Apache虚拟主机,将所有流量重定向到HTTPS版本。

<VirtualHost *:80>
  ServerName www.mywebsite.com
  Redirect permanent / https://www.mywebsite.com/
</VirtualHost>

6
在登录后,Spring 仍会发送一个带有 HTTP 地址的 Location 头信息。用户不会注意到这一点,因为您的 Apache 会立即将其重定向回 HTTPS,但这仍然是一个严重的安全问题,因为浏览器将通过不安全的通道发送会话 cookie。 - marcelj
@marcelj - 我刚在Firebug中运行了它,你是正确的。如果我找到更好的解决方案并修改了我的答案,我会尝试解决这个问题。 - Andrew Westberg - BCSH
@marcelj,您能解释一下这为什么是严重的安全风险,或者提供一个描述该风险的参考文献吗? - Nathan Ward
@NathanWard 如果攻击者拦截了HTTP请求,她可以提供一个HTTP登录表单并检索凭据。 - Paŭlo Ebermann

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接