在 Golang 中使用 Gin 获取反向代理与 TLS(到代理服务器)一起工作时遇到问题

Trouble getting reverse proxy working with TLS (to proxied server) in Golang with Gin

我的任务是创建与代理服务建立 TLS 连接所需的反向代理。我拥有的证书在每个请求中都是唯一的,并且在内存中。

我运气不太好,但我尝试了很多方法。这是我现在的位置,希望有人能提供帮助:

func proxy(c *gin.Context) {
   /* snip: magic here to get the x509 cert strings and remoteUrl */

   proxy := httputil.NewSingleHostReverseProxy(remoteUrl)

   cert := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: []byte(signedCertString)})
   key:= pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: []byte(privateKeyString)})

   certificate, err := tls.X509KeyPair(cert, key)
   if err != nil {
      c.JSON(400, gin.H{"message": "Invalid certificate"})
      return
   }

   proxy.Transport = &http.Transport{
     TLSClientConfig: &tls.Config{
       Certificates: []tls.Certificate{certificate},
       InsecureSkipVerify: true,
     }
   }

   c.Request.Host = remote.Host
   c.Request.URL.Scheme = remote.Scheme
   c.Request.URL.Host = remote.Host
   c.Request.URL.Path = remote.Path

   proxy.ServeHTTP(c.Writer, c.Request)
}

我也试过设置 RootCAs(我想也许我只是对现在 TLS 需要在这种情况下工作感到困惑):


func proxy(c *gin.Context) {
   /* snip: magic here to get the x509 cert strings and remoteUrl */

   proxy := httputil.NewSingleHostReverseProxy(remoteUrl)

   cert := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: []byte(signedCertString)})
  
   certPool := x509.NewCertPool()
   certPool.AppendCertsFromPEM(cert)

   proxy.Transport = &http.Transport{
     TLSClientConfig: &tls.Config{
       RootCAs: certPool,
       InsecureSkipVerify: true,
     }
   }

   c.Request.Host = remote.Host
   c.Request.URL.Scheme = remote.Scheme
   c.Request.URL.Host = remote.Host
   c.Request.URL.Path = remote.Path

   proxy.ServeHTTP(c.Writer, c.Request)
}

无论如何,我的目标服务器似乎没有发现代理请求是 TLS,我不确定该从哪里着手。

对于 TLS(即 https,即带有 TLS 的 http),您必须连接到正确的服务器端口。它通常是端口 43 或端口 8443。它永远不会与用于 http 的端口相同。所以这意味着要开始,服务器必须为 TLS 提供一个端口,尽管大多数都这样做。

您分享的唯一代码与服务器连接无关。

由于您没有共享任何向服务器发出请求的代码,因此无法显示错误所在。

Here is a sample

我现在无法完全重现您的设置,但原则上,您应该在 ReverseProxy.Director 函数中更改请求:

Director must be a function which modifies the request into a new request to be sent using Transport.

简而言之:

   proxy.Transport = &http.Transport{
     TLSClientConfig: &tls.Config{
       Certificates: []tls.Certificate{certificate},
       RootCAs: certPool,
       InsecureSkipVerify: true,
     }
   }

   proxy.Director = func(req *http.Request) {
       req.Host = remote.Host
       req.URL.Scheme = remote.Scheme
       req.URL.Host = remote.Host
       req.URL.Path = remote.Path
  }

  proxy.ServeHTTP(c.Writer, c.Request)

此外,您可能还需要 TLS 配置中的证书和根 CA。证书是您发送给服务器的证书,rootCA 用于验证服务器提供的证书。

我最终转而直接使用 ReverseProxy。但最大的问题是我使用的是 RootCAs 而不是 ClientCAs。这是我最终得到的结果:


clientCAs := x509.NewCertPool()
clientCAs.AppendCertsFromPEM(signedCert)
certificate, err := tls.X509KeyPair(signedCert, privateKey)

proxy := &httputil.ReverseProxy({
  Transport: &http.Transport{
    TLSClientConfig: &tls.Config{
      Certificates: []tls.Certificate{certificate},
      ClientCAs: clientCAs
    },
    Director: func (req *http.Request) {
      // Alter request here
    }
  },
})

proxy.ServeHTTP(w, r)

在此之后,一切都在顺利进行。谢谢大家!