【问题标题】:Offloading https to load balancers with Spring Security使用 Spring Security 将 https 卸载到负载均衡器
【发布时间】:2011-12-21 13:59:55
【问题描述】:

现在,负载均衡器处理 https,然后将该 https 传递给我的 Web 服务器。因此,为每个请求处理 https double。我想要做的是完全卸载 https,这样我的网络服务器就不必处理它了。

如果 Web 服务器认为所有请求都是 http,我该如何配置 Spring Security 和 JSP 页面?显然,我必须修改配置中的<intercept-url> 元素,使其requires-channel 属性始终为httpany。在我的 JSP 页面中,我必须在 <c:url value=''/> 链接前面加上 ${secureUrl}${nonSecureUrl},具体取决于生成的页面是 https 还是 http。来自控制器的重定向也需要像这样修改...还有什么?

修改 JSP 页面中的所有链接以包含方案和主机似乎相当痛苦。有没有更好的方法来做到这一点?

【问题讨论】:

    标签: jsp spring-mvc https spring-security load-balancing


    【解决方案1】:

    如果您在负载均衡器处终止 SSL,那么您的负载均衡器应发送一个标头,指示最初请求的协议。例如,F5 增加了 X-Forwarded-Proto。

    您可以从这里创建自定义ChannelProcessors,以查看此标头而不是查看request.isSecure()。然后你可以继续使用<intercept-url requires-channel="https"> 和相关的<c:url>

    步骤:

    1. 子类 SecureChannelProcessorInsecureChannelProcessor 覆盖 decide()。在decide() 中检查负载均衡器发送的标头。

      @Override
      public void decide(FilterInvocation invocation, Collection<ConfigAttribute> config) throws IOException, ServletException {
      
        for (ConfigAttribute attribute : config) {
            if (supports(attribute)) {
                if (invocation.getHttpRequest().
                        getHeader("X-Forwarded-Proto").equals("http")) {
                    entryPoint.commence(invocation.getRequest(),
                        invocation.getResponse());
                }
            }
        }
      }
      
    2. 然后使用 BeanPostProcessorChannelDecisionManagerImpl bean 上设置这些 ChannelProcessor。请参阅此Spring Security FAQ,了解为什么/如何为此使用BeanPostProcessor

    【讨论】:

    • 尝试了上述步骤,确定方法没有被调用,还有什么需要配置的吗?
    【解决方案2】:

    要完成伟大的 sourcedelica 答案,这里是完整的代码:

    对于第 1 步:

    @Component
    public class SecureChannelProcessorHack extends SecureChannelProcessor {
    
    @Override
    public void decide(FilterInvocation invocation, Collection<ConfigAttribute> config) throws IOException, ServletException {
        for (ConfigAttribute attribute : config) {
            if (supports(attribute)) {
                if ("http".equals(invocation.getHttpRequest().getHeader("X-Forwarded-Proto"))) {
                    getEntryPoint().commence(invocation.getRequest(),
                            invocation.getResponse());
                }
            }
        }
    }
    }
    
    
    
    @Component
    public class InsecureChannelProcessorHack extends InsecureChannelProcessor {
    
    @Override
    public void decide(FilterInvocation invocation, Collection<ConfigAttribute> config) throws IOException, ServletException {
        for (ConfigAttribute attribute : config) {
            if (supports(attribute)) {
                if ("https".equals(invocation.getHttpRequest().getHeader("X-Forwarded-Proto"))) {
                    getEntryPoint().commence(invocation.getRequest(),
                            invocation.getResponse());
                }
            }
        }
    }
    }
    

    第二步:

    @Configuration
    public class LoadBalancerHack implements BeanPostProcessor {
    
    @Inject
    SecureChannelProcessorHack secureChannelProcessorHack;
    
    @Inject
    InsecureChannelProcessorHack insecureChannelProcessorHack;
    
    @Value("${behind.loadbalancer?false}")
    boolean behindLoadBalancer;
    
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (behindLoadBalancer && bean instanceof ChannelDecisionManagerImpl) {
            System.out.println("********* Post-processing " + beanName);
            ((ChannelDecisionManagerImpl) bean).setChannelProcessors(newArrayList(
                    insecureChannelProcessorHack,
                    secureChannelProcessorHack
            ));
        }
        return bean;
    }
    
    }
    

    【讨论】:

      【解决方案3】:

      看起来 Grails 支持将此作为安全插件的一部分。查看http://grails-plugins.github.com/grails-spring-security-core/docs/manual/guide/17%20Channel%20Security.html 的底部部分,他们讨论了检查请求标头,这是 LB 将设置的。

      grails.plugins.springsecurity.secureChannel.useHeaderCheckChannelSecurity = true
      grails.plugins.springsecurity.secureChannel.secureHeaderName = '...'
      grails.plugins.springsecurity.secureChannel.secureHeaderValue = '...'
      grails.plugins.springsecurity.secureChannel.insecureHeaderName = '...'
      grails.plugins.springsecurity.secureChannel.insecureHeaderValue = '...'
      

      【讨论】:

        猜你喜欢
        • 2016-05-12
        • 2022-01-01
        • 2018-12-11
        • 2021-12-07
        • 2016-07-25
        • 2014-02-12
        • 2020-05-08
        • 1970-01-01
        • 2015-05-22
        相关资源
        最近更新 更多