代理 https 时强制客户端主机名

lf2*_*215 4 proxy ssl-certificate go

我正在使用毒代理。我遇到了这个确切的问题curl问题中提到的两个解决方案都有效(解决方案 a解决方案 b),但我无法使用curl。我需要使用 go 标准net/http库。

有没有什么方法可以net/http以这样的方式使用,我可以明确地告诉它代理正在使用哪个主机,以便它可以看到证书是有效的?

我尝试过在 net/http.Request 上设置HostAuthority标头,但这不起作用。

细节

Toxiproxy 输出:

代理=[::]:22002 上游=maps.googleapis.com:443

我的代码:

url := "https://localhost:22002/maps/api/geocode/json..."
req, err := http.NewRequest("GET", url, nil)
req.Host = "maps.googleapis.com"
req.Header.Set("Host", "maps.googleapis.com")
res, err := httpClient.Do(req)
Run Code Online (Sandbox Code Playgroud)

错误:

x509:证书对 *.googleapis.com、*.clients6.google.com、*.cloudendpointsapis.com、cloudendpointsapis.com、googleapis.com 有效,不适用于 localhost

Jim*_*imB 5

您需要设置该http.Request.Host字段,以便http请求具有正确的标头

req.Host = "maps.googleapis.com"
Run Code Online (Sandbox Code Playgroud)

tls.Config.ServerName您还需要在SNI 和主机名验证字段中设置主机名。

如果您已经为您的 配置了传输httpClient,则可以像这样设置:

httpClient.Transport.(*http.Transport).TLSClientConfig = &tls.Config{
    ServerName: "maps.googleapis.com",
}
Run Code Online (Sandbox Code Playgroud)

或者对于小程序,您可以覆盖默认值:

http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{
    ServerName: "maps.googleapis.com",
}
Run Code Online (Sandbox Code Playgroud)

或者为您的程序创建自定义传输

var httpTransport = &http.Transport{
    Proxy: http.ProxyFromEnvironment,
    DialContext: (&net.Dialer{
        Timeout:   30 * time.Second,
        KeepAlive: 30 * time.Second,
        DualStack: true,
    }).DialContext,
    MaxIdleConns:          100,
    IdleConnTimeout:       90 * time.Second,
    TLSHandshakeTimeout:   10 * time.Second,
    ExpectContinueTimeout: 1 * time.Second,
    TLSClientConfig: &tls.Config{
        ServerName: "maps.googleapis.com",
    },
}
Run Code Online (Sandbox Code Playgroud)

只需确保重用传输,并且不要为每个请求创建一个新传输。

  • 启用 TLS 后,HTTP 标头将被加密。服务器必须先选择一个证书进行解密,然后才能检查主机标头。这就是 ServerName 字段的用途;它作为 TLS 握手的一部分发送(称为 [SNI](https://en.wikipedia.org/wiki/Server_Name_Induction))。解密 HTTP 标头后,服务器查看主机标头以将请求路由到正确的虚拟主机。这就是为什么您需要设置这两个值。 (2认同)