使用Spring Security配置应用程序以接受HTTP请求并发送HTTPS响应

时间:2015-04-05 13:38:18

标签: java spring spring-mvc spring-security

我是Spring框架的新手,我搜索了与此主题相关的每个可能的SO链接,但可以找到任何正确的解决方案。 我有一个在JBoss Wildfly上运行的应用程序。它位于AWS EC2实例上,该实例位于Elastic Load Balancer(ELB)后面。 ELB中配置了SSL,因此它只接受来自客户端的HTTPS请求,但我的应用服务器只通过HTTP与ELB通信。我的应用程序使用Spring MVC和Spring Security进行前端/安全管理。 我的security-context.xml文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd">

<context:property-placeholder location="/WEB-INF/config.properties" />
<context:annotation-config></context:annotation-config>
<context:component-scan base-package="com.etech.security">          </context:component-scan>
<security:authentication-manager>
    <security:authentication-provider>
        <security:user-service>
            <security:user name="xxx@xxxx.com"
                authorities="admin" password="xxxxxxxx" />
        </security:user-service>
</security:authentication-provider>
</security:authentication-manager>
<security:http use-expressions="true">
    <security:intercept-url pattern="/" access="isAuthenticated()" />
    <security:intercept-url pattern="/dashboard"
        access="isAuthenticated()" />
    <security:intercept-url pattern="/resources/**" access="permitAll" />
    <security:intercept-url pattern="/login" access="permitAll" />
    <security:intercept-url pattern="/**" access="denyAll" />
    <security:form-login login-page="/login"
        authentication-success-handler-ref="asyncAuthenticationSuccessHandler"
        authentication-failure-handler-ref="asyncAuthenticationFailureHandler" />
    <security:logout logout-url="/logout" logout-success-url="/" />

</security:http>
<bean id="asyncAuthenticationSuccessHandler"
    class="com.etech.security.AsyncAuthenticationSuccessHandler">
<constructor-arg ref="supportMailPassword"></constructor-arg>
</bean>

此设置的问题是,一旦通过身份验证,应用程序就会返回到客户端的HTTP链接,客户端无法访问该链接,因为ELB仅允许HTTPS URL。如下所示:

客户--HTTPS ---&gt; ELB --- HTTP - &gt;应用服务器/应用

客户端&lt; - HTTP-- ELB&lt; --- HTTP --- AppServer / Application

但实际上应该这样做,

客户--HTTPS ---&gt; ELB --- HTTP - &gt;应用服务器/应用

客户端&lt; - HTTPS-- ELB&lt; --- HTTPS --- AppServer / Application

对此有什么正确的方法,我是否需要使用在身份验证/处理后绑定到Response的任何类型的Filter,我可以将响应URL更改为HTTPS?

1 个答案:

答案 0 :(得分:1)

在深入研究问题之后,我发现这主要是由于Spring Dispatcher Servlet将入站连接检测为不安全,即所有连接都是通过HTTP进行的,这将导致所有出站连接都通过HTTP进行。

Spring会通过以下方法调用检测到这一点:HttpServletRequest.isSecure(),这将始终返回false,因为从ELB到Application Server的连接是通过HTTP而不是HTTPS。

有一个很好的blog post描述了这个完全相同的问题,并发布了一个我自己使用的简单解决方案。

解决方案是使用放置在过滤器链顶部的过滤器。它会拦截所有传入的请求,用自定义的HttpServletRequest替换入站的HttpServletRequest,这将使isSecure()方法返回true。然后Spring调度程序Servlet会检测到这一点并将HTTPS响应发送回客户端。

步骤很简单:

  1. 创建自定义HttpServletRequestWrapper

    public class CustomWrapper extends HttpServletRequestWrapper
    {
    
        public CustomWrapper(HttpServletRequest request) {
            super(request);
    
        }
    
       public boolean isSecure()
       {
            return true;
       }
    
        public String getScheme()
       {
           return "https";
       }
    }
    
  2. 创建一个可以使用此包装器的过滤器

    public class CustomFilter implements Filter 
    {
    
        @Override
        public void destroy() {
    
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException 
        {
            CustomWrapper wrapper = new CustomWrapper((HttpServletRequest) request);
            chain.doFilter(wrapper, response);
    
        }
    
        @Override
        public void init(FilterConfig arg0) throws ServletException {
    
       }  
    

    }

  3. 在web.xml中,在任何其他过滤器之前添加此过滤器,包括Spring Security Filter chain。