在 Google 前端负载均衡器后面运行时如何正确从 Spring Boot 2.3 重定向到 HTTPS

Posted

技术标签:

【中文标题】在 Google 前端负载均衡器后面运行时如何正确从 Spring Boot 2.3 重定向到 HTTPS【英文标题】:How to properly Redirect from Spring Boot 2.3 to HTTPS when running behind a Google Front End Load Balancer 【发布时间】:2020-10-13 14:05:42 【问题描述】:

我有一个 Spring Boot 应用程序在 GKE 上通过入口控制器使用 Google https 负载均衡器运行。我正在寻找的行为是让 Spring Boot 应用程序在收到 http 请求时重定向到 https。在 Spring Boot 2.2 及更早的版本中,我可以使用以下代码和配置来做到这一点。

我的应用程序 yaml 中的配置

server:
  port: 8877
  use-forward-headers: true # this should make it understand X-Forwarded-Proto header 

在我的 Spring Security 配置中我做了

 @Override
  protected void configure(HttpSecurity http) throws Exception 

    /* When the app is running on GKE traffic will come in through the
     * GCP http load balancer. Which will set the X-Forwarded-Proto
     * header to http or https. When the app runs on a dev machine
     * these headers are not set.
     *
     * see https://cloud.google.com/load-balancing/docs/https/
     *
     * The code forces ssl if the x forwarded proto header is present
     * as that indicates the app is online and accessible to the
     * wider internet.
     *
     */
    http.requiresChannel()
        .requestMatchers(r -> r.getHeader("X-Forwarded-Proto") != null)
        .requiresSecure();
   // more stuff  omitted  
  

在 Spring Boot 2.3 server.use-forward-headers 已弃用我将配置更改为

server:
  port: 7777
  forward-headers-strategy: native
  tomcat:
    remoteip:
      protocol-header: "X-Forwarded-Proto"
      remote-ip-header: "X-Forwarded-For"

我没有对需要安全通道的代码进行任何更改。但是,当像 https://example.com 这样的请求通过 GCP 负载均衡器到达引导时,它不会被识别为安全连接,并且重定向 https://example.com 是从 Spring Boot 发送的。这会导致浏览器说检测到无限重定向循环。

问题在通过 Ingress 控制器配置的 GCP 负载均衡器后面的 GKE 上运行的 Spring Boot 2.3 上从 http 重定向到 https 的正确方法是什么?

【问题讨论】:

【参考方案1】:

Spring Boot 依赖于 Tomcat 来评估传入的请求,以确定该请求是否应被视为“安全”。 Tomcat remote IP valve 正在查看两位信息以评估请求是否安全。

    向tomcat发送请求的负载均衡器/代理的IP地址 x-forwarded-proto http 标头的值

在tomcat配置中称为内部代理的负载均衡器的IP地址必须在受信任列表中,并且x-forwaded-proto必须是https,以便tomcat认为请求安全。否则,将发送重定向。

谷歌负载均衡器正在发送带有x-forwaded-proto: https 的请求,但源IP 是google range 35.191.0.0/16130.211.0.0/22 之一,因此tomcat 认为来自GCP 负载均衡器的https 请求不安全,发回重定向.从而导致浏览器抱怨的无限重定向循环。

Spring Boot 使用属性 server.tomcat.remoteip.internal-proxies 配置 tomcat 远程 IP 地址,该属性使用下面的正则表达式具有来自 RFC 1918 的私有 IP 地址的默认值。

10\\.\\d1,3\\.\\d1,3\\.\\d1,3|192\\.168\\.\\d1,3\\.\\d1,3|169\\.254\\.\\d1,3\\.\\d1,3|127\\.\\d1,3\\.\\d1,3\\.\\d1,3|172\\.1[6-9]1\\.\\d1,3\\.\\d1,3|172\\.2[0-9]1\\.\\d1,3\\.\\d1,3|172\\.3[0-1]1\\.\\d1,3\\.\\d1,3|0:0:0:0:0:0:0:1|::1

Tomcat 不知道如何比较 ip 地址范围,因此必须将 google 源 ips 转换为正则表达式才能工作。

server:
  port: 7777
  forward-headers-strategy: native
  tomcat:
    remoteip:
      protocol-header: "X-Forwarded-Proto"
      remote-ip-header: "X-Forwarded-For"
      internal-proxies: ".*" # should Java regex to match ip address range of the load balancer servers. Not a best practice to trust all ip addresses. 

【讨论】:

在我的情况下,使用ForwardedHeaderFilter ***.com/a/67377536/986942修复

以上是关于在 Google 前端负载均衡器后面运行时如何正确从 Spring Boot 2.3 重定向到 HTTPS的主要内容,如果未能解决你的问题,请参考以下文章

如何拒绝对没有主机标头的 Google 外部 HTTPS 负载均衡器的请求?

Google Maglev 牛逼的网络负载均衡器(转)

如何使 HTTP 调用到达亚马逊 AWS 负载均衡器后面的所有实例?

在负载均衡器后面运行多个 daphne 实例:django-channels

如何在负载均衡器后面强制 Spring Security 发出 https 重定向请求

lvs IP负载均衡