使用Spring Security卸载https到负载均衡器



现在,负载均衡器处理https,然后将https传递到我的web服务器。因此,处理每个请求的https加倍。我想做的是完全卸载https,这样我的web服务器就不必处理它了。

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

修改JSP页面中的所有链接以包含方案和主机似乎相当痛苦。有更好的方法吗?

如果您在负载均衡器上终止SSL,那么负载均衡器应该发送一个头,指示最初请求的协议。例如,F5增加了x - forward - proto。

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

步骤:

  1. 子类SecureChannelProcessor和InsecureChannelProcessor覆盖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. 然后使用BeanPostProcessor在ChannelDecisionManagerImpl bean上设置这些ChannelProcessors。关于为什么/如何使用BeanPostProcessor,请参阅Spring Security FAQ。

完整的源代码如下:

对于步骤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;
}
}

看起来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 = '...'

最新更新