在Go中实现curl --proxy-insecure行为:信任不安全代理但验证目标证书
Go实现仅跳过代理TLS证书验证的HTTPS请求
要实现类似https_proxy="https://insecureproxy.net" curl https://somesecureurl.net/ --proxy-insecure的行为,核心是单独控制代理与目标站点的TLS证书验证逻辑,不能直接全局设置InsecureSkipVerify: true。以下是具体实现方案:
核心思路
http.Transport的TLSClientConfig负责目标站点的TLS验证,而ProxyDialTLSContext可以自定义与HTTPS代理建立TLS连接的逻辑。我们可以在后者中跳过代理的证书验证,同时保持前者的安全验证规则。
完整代码示例
package main import ( "context" "crypto/tls" "net" "net/http" "net/url" "strings" ) func main() { // 创建自定义Transport transport := &http.Transport{ // 目标站点使用默认TLS配置,严格验证证书 TLSClientConfig: &tls.Config{ InsecureSkipVerify: false, // 默认值,可省略 }, // 自定义与代理的TLS连接逻辑,跳过代理证书验证 ProxyDialTLSContext: func(ctx context.Context, network, addr string) (net.Conn, error) { // 先建立TCP连接到代理 dialer := &net.Dialer{} conn, err := dialer.DialContext(ctx, network, addr) if err != nil { return nil, err } // 解析代理主机名,用于设置SNI proxyHost := addr[:strings.Index(addr, ":")] // 与代理建立TLS连接,跳过证书验证 tlsConn := tls.Client(conn, &tls.Config{ InsecureSkipVerify: true, ServerName: proxyHost, }) // 完成TLS握手 if err := tlsConn.HandshakeContext(ctx); err != nil { conn.Close() return nil, err } return tlsConn, nil }, } // 设置HTTPS代理地址 proxyURL, _ := url.Parse("https://insecureproxy.net") transport.Proxy = http.ProxyURL(proxyURL) // 创建HTTP客户端 client := &http.Client{Transport: transport} // 发送请求到目标站点 resp, err := client.Get("https://somesecureurl.net/") if err != nil { panic(err) } defer resp.Body.Close() // 后续处理响应... }
关键细节说明
- ProxyDialTLSContext的作用:当使用HTTPS代理时,客户端会先通过这个函数与代理建立TLS连接,这里的TLS配置仅作用于代理,不会影响目标站点。
- ServerName的设置:即使跳过代理证书验证,设置SNI(Server Name Indication)可以让代理返回对应域名的自签名证书,避免不必要的握手错误。
- 目标站点的安全保障:
TLSClientConfig保持默认的严格验证,确保目标站点somesecureurl.net的合法证书会被正常校验。
内容的提问来源于stack exchange,提问作者q84fh
相关产品推荐
相关产品推荐

