如何在golang中进行代理和TLS。

3

我正在尝试通过代理路由我的请求,并在TLS配置中发送cert.pem。以下代码会引发此错误 - proxyconnect tcp: tls: first record does not look like a TLS handshake。当我将代理URL从https更改为HTTP时,相同的代码有效。但是,在Python中使用https代理URL也有效。以下是到目前为止的我的代码:

certs := x509.NewCertPool()
pemFile, err := ioutil.ReadFile("cert.pem")
if err != nil {
    return
}
certs.AppendCertsFromPEM(pemFile)
tlsConfig := &tls.Config{
    RootCAs: certs,
}

proxyUrl, err := url.Parse("https://someproxyurlhere.com:8080")
if err != nil {
    return
}

t := &http.Transport{
    TLSClientConfig: tlsConfig,
    Proxy:           http.ProxyURL(proxyUrl),
}

client := http.Client{
    Transport: t,
}

reqBody := "some JSON body here"

buff, err := json.Marshal(reqBody)
if err != nil {
    return
}

req, err := http.NewRequest(http.MethodPost, "https://someurlhere.com", bytes.NewBuffer(buff))
if err != nil {
    return
}

res, err := client.Do(req)
if err != nil {
    // Error here - proxyconnect tcp: tls: first record does not look like a TLS handshake
    return
}
defer res.Body.Close()

Python 代码

import requests
os.environ['HTTPS_PROXY'] = 'https://someproxyurlhere.com:8080'
response = requests.post("https://someurlhere.com",
                           json={'key': 'value'},
                           verify='cert.pem')
print(str(response.content))

然而,带有https的代理URL在Python中有效。以下是示例代码来证明这一点:import requests proxies = { 'https': 'https://someproxyurlhere.com:8080' } response = requests.get('https://www.example.com', proxies=proxies) print(response.content)输出应该返回请求网站的内容。此外,运行openssl s_client -connect someproxyurlhere.com:8080 命令可以证明代理本身确实支持HTTPS协议。通常情况下,即使对于支持HTTPS的URL,代理也只通过HTTP进行访问(当执行CONNECT命令时,代理会将连接隧道到最终服务器,从而保留端到端的安全性)。如果同一代理和端口既可通过HTTP又可通过HTTPS访问,这尤其奇怪。 - Steffen Ullrich
@SteffenUllrich 更新了 Python 代码。 - androidGuy
os.environ['HTTPS_PROXY'] = 'https://someproxyurlhere.com:8080' - requests并不关心此处给出的协议(https vs http)。它将仅使用IP和端口以纯HTTP连接到代理。 - Steffen Ullrich
1个回答

2
当我将代理URL从https更改为HTTP时,相同的代码就可以工作了。
这是因为您正在使用需要通过HTTP访问而不是HTTPS访问的HTTP代理,即使对于https://.. URL也是如此。这通常是HTTPS代理的工作方式。请注意,虽然在理论上代理可以嗅探它是否获得了明文或TLS连接,但实际上代理(和服务器)使用不同的端口进行HTTP和HTTPS - 因此,如果它在一个端口上使用HTTP工作,则很可能无法在相同的端口上使用HTTPS工作。 proxyconnect tcp: tls:第一条记录看起来不像是TLS握手。
这是因为代理以纯HTTP错误回答奇怪的HTTP请求(实际上是TLS握手的开始)。
但是,带有https的代理URL在Python中可以工作。
虽然看起来它可以工作,但实际上并不是这样。即使给出https://作为URL,Python请求仍将使用纯HTTP向代理发送请求。
您可以尝试与代理本身建立简单的TLS连接,例如使用Python或openssl s_client。它很可能会失败,因为代理实际上并不期望TLS。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接