【问题标题】:Spring Security with HTTPS on CloudFoundryCloudFoundry 上使用 HTTPS 的 Spring Security
【发布时间】:2013-04-25 10:04:05
【问题描述】:

我尝试在 Spring Security xml 中使用以下配置访问 CloudFoundry 上的应用程序

<intercept-url pattern="/signup*" access="permitAll" requires-channel="https" />

但它给了我错误这个网页有一个重定向循环

但是,当我将其更改为requires-channel="http" 时,我可以正常看到我的页面。在这两种情况下,我都在我的应用程序中使用了https。这是预期的行为吗?

【问题讨论】:

    标签: spring-mvc spring-security cloud-foundry


    【解决方案1】:

    首先,退后一步,这个 (https://johnpfield.wordpress.com/2014/09/10/configuring-ssltls-for-cloud-foundry/) 为问题的性质提供了很好的背景。

    关键段落是

    “这里的威胁模型是云的入口点是高可用性、安全的代理服务器。一旦流量穿过该边界,它就位于受信任的子网上。事实上,运行 Tomcat 应用程序服务器的实际 IP 地址和端口号在云外部是不可见的。获得对该端口的 HTTP 请求的唯一方法是通过安全代理。这种模式是安全架构从业者中公认的最佳实践。”

    因此,我们可能不希望或不需要 SSL,但请继续阅读以了解在使用 Cloud Foundry 上部署的 Spring Security 时如何避免 https 重定向问题。

    您将在 Cloud Foundry 安装的边界处拥有一个负载平衡器、HAProxy 或某种终止 SSL 的代理。作为惯例,无论您使用什么,都应配置为设置 X-Forwarded-For 和 X-Forwarded-Proto 标头。请求标头“X-Forwarded-Proto”包含值 http 或 https,具体取决于原始请求,您需要使用此标头参数进行进一步的安全决策。

    最干净的方法是在容器级别,这样 Spring Security 的行为与部署容器无关。一些典型的配置选项如下

    1) 雄猫

    Tomcat 应该配置一个 RemoteIPValve,正如 here 中描述的那样

    好消息是 Cloud Foundry 的 Java buildpack 已经为您完成了这项工作,如 here 所示

    2) Spring Boot(嵌入式 Tomcat)

    由于 Tomcat 是嵌入的,Java buildpack 中的 Tomcat 配置不会被激活(参见 buildpack Detection Criterion),因此需要一些内部 Spring Boot 配置。幸运的是,使用 Spring Boot 进行配置非常简单,您可以按照 here 的说明打开 Tomcat 的 RemoteIPValve,只需定义

    server.tomcat.remote_ip_header=x-forwarded-for

    server.tomcat.protocol_header=x-forwarded-proto

    这两种方法都会导致 Tomcat 阀覆盖 ServletRequest.isSecure() 行为的相同结果,因此应用程序不知道任何代理的使用情况。请注意,只有在设置了“X-Forwarded-Proto”标题时才会使用阀门。

    或者,如果您真的想进入低级别,您可以深入了解 Spring Security 的核心,如 here 所示。作为这项工作的一部分,有一些有用的发现关于如何通过 Servlet API 使“X-Forwarded-Proto”标头可用于在https://github.com/BroadleafCommerce/BroadleafCommerce/issues/424的 cmets 上共享的其他容器(WebLogic、JBoss、Jetty、Glassfish) /p>

    作为附加说明,CloudFlare 还可以充当 SSL 终止反向代理(这是通过 PWS 推荐的方法,如 here 所讨论的),它 does 确实转发相关标头。

    参考文献

    https://stackoverflow.com/a/28300485/752167

    http://experts.hybris.com/answers/33612/view.html

    https://github.com/cloudfoundry/java-buildpack/commit/540633bc932299ef4335fde16d4069349c66062e

    https://support.run.pivotal.io/entries/24898367-Spring-security-with-https

    http://docs.spring.io/spring-boot/docs/current/reference/html/howto-embedded-servlet-containers.html#howto-use-tomcat-behind-a-proxy-server

    【讨论】:

      【解决方案2】:

      当我尝试使用 Spring Security 使用 HTTPS 保护我的页面时,我遇到了同样的问题。

      从 CloudFoundry Support 的讨论中,他们似乎“在路由器上终止 SSL 连接”。请参阅“Is it possible to visit my application via SSL (HTTPS)?”。

      一年多之后,我找不到关于这个问题的更多信息。

      【讨论】:

      • 现在有很多关于这个问题的进一步信息,所以我把它总结在一个新的答案中
      • 不幸的是,此答​​案中的链接似乎已失效
      【解决方案3】:

      如果它仍然有用...我发现 this post 提供了解决类似问题的线索。

      问题是 org.springframework.security.web.access.channel.SecureChannelProcessor bean 正在使用 ServletRequest.isSecure() 来决定是接受连接还是重定向,这在云内部变得混乱。

      对该 bean 的以下覆盖似乎在 BlueMix 下完成了这项工作 - 不确定 $WSSC 请求标头是否适用于所有环境。

      @Component
      public class ChannelProcessorsPostProcessor implements BeanPostProcessor {
      
          @Override
          public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
              if (bean instanceof SecureChannelProcessor) {
                  final SecureChannelProcessor scp = (SecureChannelProcessor) bean;
                  return new ChannelProcessor() {
                      @Override
                      public void decide(FilterInvocation invocation,
                              Collection<ConfigAttribute> config) throws IOException,
                              ServletException {
                          HttpServletRequest httpRequest = invocation.getHttpRequest();
                          // Running under BlueMix (CloudFoundry in general?), the
                          //   invocation.getHttpRequest().isSecure() in SecureChannelProcessor
                          //   was always returning false
                          if ("https".equals(httpRequest.getHeader("$WSSC"))) {
                              return;
                          }
                          scp.decide(invocation, config);
                      }
      
                      @Override
                      public boolean supports(ConfigAttribute attribute) {
                          return scp.supports(attribute);
                      }
                  };
              }
      
              return bean;
          }
      
          @Override
          public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException {
      
              return bean;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-07-16
        • 2015-10-19
        • 1970-01-01
        • 2015-06-08
        • 1970-01-01
        • 2018-10-13
        • 1970-01-01
        • 2017-09-20
        相关资源
        最近更新 更多