在Golang中使用Gin实现TLS的反向代理时遇到了问题。

huangapple go评论161阅读模式
英文:

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

问题

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

我尝试了很多方法,但都没有成功。以下是我目前的进展,希望有人可以帮助我:

func proxy(c *gin.Context) {
   /* 省略:在这里获取x509证书字符串和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": "无效的证书"})
      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) {
   /* 省略:在这里获取x509证书字符串和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的,我真的不确定接下来该怎么做。

英文:

I've been tasked with creating a reverse proxy that is required to make a TLS connection to the proxied service. The certificates I have are unique per request, and in-memory.

I haven't had much luck getting it right, and I've tried a number of things. Here's where I'm at now, hopefully someone can help:

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)
}

I've also tried setting RootCAs (figuring maybe I'm just twisted about now TLS needs to work in this scenario):


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)
}

In any case, the server I'm targeting doesn't seem to pick up that the proxied request was TLS, and I'm not really sure where to proceed with this.

答案1

得分: 1

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

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

由于您没有分享任何向服务器发出请求的代码,无法显示出错的位置。

这里是一个示例

英文:

For TLS (ie https, which is http with TLS) you must connect to the correct server port. It is usually port 43 or port 8443. It is never the same as the port used for http. So this means that to start, the server must provide a port for TLS, although most do.

The only code you've shared has nothing to do with the connection to the server.

Since you've not shared any of the code making the request to the server, it is not possible to show where it is wrong.

Here is a sample

答案2

得分: 1

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

> Director必须是一个函数,它将请求修改为使用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配置中同时使用证书和根证书。证书是你发送给服务器的证书,而根证书用于验证服务器提供的证书。

英文:

I am unable to fully reproduce your setup right now, but in principle, you are supposed to alter the request inside ReverseProxy.Director function:

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

So in short:

   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)

Also you might need both the certificates and the rootCAs in the TLS config. The certificates are those you send to the server, and the rootCA is for verifying those presented by the server.

答案3

得分: 0

我最终决定直接使用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) {
      // 在这里修改请求
    }
  },
})

proxy.ServeHTTP(w, r)

在这之后,一切都正常工作了。谢谢大家!

英文:

I ended up switching to use ReverseProxy directly. But the big problem is I was using RootCAs and not ClientCAs. Here is what I ended up with:


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)

After this, everything is working swimmingly. Thanks, all!

huangapple
  • 本文由 发表于 2021年10月2日 00:04:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/69408878.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定