通过代理的HTTPS完全加密,包括SSL CONNECT。

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

HTTPS through proxy completely encrypted, including SSL CONNECT

问题

我正在尝试测试一个代理,该代理期望立即进行SSL握手,即使客户端将使用SSL CONNECT方法。问题是,我的Golang和Python测试代码似乎都有相同的缺陷。它们以明文连接到代理,然后发出CONNECT请求,但代理拒绝此请求,因为它期望进行SSL握手。

有人知道如何强制使用可用的标准库使任一技术使用SSL连接到代理吗?

谢谢。

以下是示例代码:

Python代码:

#!/usr/bin/python

try:
    import urllib2

    proxy = urllib2.ProxyHandler({'https': "myproxyip:6881"})
    opener = urllib2.build_opener(proxy)
    urllib2.install_opener(opener)
    print urllib2.urlopen('https://www.google.ca').read()

except Exception as err:
    print err


try:
    import httplib

    c = httplib.HTTPSConnection('myproxyip', 6881)
    c.set_tunnel('google.ca', 443)
    c.request('GET', '/')
    res = c.getresponse()
    print res.status, res.reason

except Exception as err:
    print err

Golang代码:

// vim: ft=go ts=4 sw=4 et ai:
package main

import (
    "net/http"
    "log"
    "io/ioutil"
    "time"
    "crypto/tls"
    "net/url"
)

var use_proxy = true
var proxy = "https://myproxyip:6881"
var req_url = "https://google.ca"
var n_seconds time.Duration = 15
var period = time.Second * n_seconds
var n_threads = 50
var thread_start_delay time.Duration = 1

func http_fetch(req_url string) {
    tr := http.Transport {
        TLSClientConfig: &tls.Config {
            InsecureSkipVerify: true,
        },
    }
    proxy_url, err := url.Parse(proxy)
    if err != nil {
        log.Fatal(err)
    }
    if use_proxy {
        tr.Proxy = http.ProxyURL(proxy_url)
    }
    client := &http.Client{}
    client.Transport = &tr

    req, err := http.NewRequest("GET", req_url, nil)
    if err != nil {
        log.Fatal(err)
    }
    req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36")

    res, err := client.Do(req)
    if err != nil {
        log.Fatal(err)
    }
    body, err := ioutil.ReadAll(res.Body)
    defer res.Body.Close()
    document := string(body)
    print(document)
}


func main() {
    println("main: Starting", n_threads, "threads to hammer", req_url, "every", n_seconds, "seconds, ctrl-c to quit...")
    done := make(<-chan bool)
    for i:= 0; i < n_threads; i++ {
        go func(thread_id int) {
            println("thread", thread_id, ": starting periodic_hammer")
            for {
                println("thread", thread_id, ": fetching", req_url)
                http_fetch(req_url)
                println("thread", thread_id, ": done, sleeping for", n_seconds, "seconds")
                time.Sleep(period)
            }
        }(i+1)
        println("main: delaying", thread_start_delay, "seconds before starting next thread")
        time.Sleep(thread_start_delay * time.Second)
    }
    <-done
}

希望对你有所帮助!

英文:

I am trying to test a proxy that is expecting an SSL handshake immediately, even if the client is going to use an SSL CONNECT method. The problem is that my Golang and Python test code both seem to have the same flaw. They connect to the proxy in the clear, and then issue a CONNECT, but the proxy rejects this because it is expecting an SSL handshake.

Does anyone know how to force either technology to use SSL to the proxy using available standard libraries?

Thanks.

Sample code follows:

#!/usr/bin/python
try:
import urllib2
proxy = urllib2.ProxyHandler({&#39;https&#39;: &quot;myproxyip:6881&quot;})
opener = urllib2.build_opener(proxy)
urllib2.install_opener(opener)
print urllib2.urlopen(&#39;https://www.google.ca&#39;).read()
except Exception as err:
print err
try:
import httplib
c = httplib.HTTPSConnection(&#39;myproxyip&#39;, 6881)
c.set_tunnel(&#39;google.ca&#39;, 443)
c.request(&#39;GET&#39;, &#39;/&#39;)
res = c.getresponse()
print res.status, res.reason
except Exception as err:
print err

and golang

// vim: ft=go ts=4 sw=4 et ai:
package main
import (
&quot;net/http&quot;
&quot;log&quot;
&quot;io/ioutil&quot;
&quot;time&quot;
&quot;crypto/tls&quot;
&quot;net/url&quot;
)
var use_proxy = true
var proxy = &quot;https://myproxyip:6881&quot;
var req_url = &quot;https://google.ca&quot;
var n_seconds time.Duration = 15
var period = time.Second * n_seconds
var n_threads = 50
var thread_start_delay time.Duration = 1
func http_fetch(req_url string) {
tr := http.Transport {
TLSClientConfig: &amp;tls.Config {
InsecureSkipVerify: true,
},
}
proxy_url, err := url.Parse(proxy)
if err != nil {
log.Fatal(err)
}
if use_proxy {
tr.Proxy = http.ProxyURL(proxy_url)
}
client := &amp;http.Client{}
client.Transport = &amp;tr
req, err := http.NewRequest(&quot;GET&quot;, req_url, nil)
if err != nil {
log.Fatal(err)
}
req.Header.Set(&quot;User-Agent&quot;, &quot;Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36&quot;)
res, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
body, err := ioutil.ReadAll(res.Body)
defer res.Body.Close()
document := string(body)
print(document)
}
func main() {
println(&quot;main: Starting&quot;, n_threads, &quot;threads to hammer&quot;, req_url, &quot;every&quot;, n_seconds, &quot;seconds, ctrl-c to quit...&quot;)
done := make(&lt;-chan bool)
for i:= 0; i &lt; n_threads; i++ {
go func(thread_id int) {
println(&quot;thread&quot;, thread_id, &quot;: starting periodic_hammer&quot;)
for {
println(&quot;thread&quot;, thread_id, &quot;: fetching&quot;, req_url)
http_fetch(req_url)
println(&quot;thread&quot;, thread_id, &quot;: done, sleeping for&quot;, n_seconds, &quot;seconds&quot;)
time.Sleep(period)
}
}(i+1)
println(&quot;main: delaying&quot;, thread_start_delay, &quot;seconds before starting next thread&quot;)
time.Sleep(thread_start_delay * time.Second)
}
&lt;-done
}

答案1

得分: 1

使用https代理仅支持Go 1.10及以上版本。根据草案发布说明

> 在客户端方面,现在可以将HTTP代理(通常由ProxyFromEnvironment配置)指定为https:// URL,这意味着客户端在发出标准的代理HTTP请求之前通过HTTPS连接到代理。 (以前,HTTP代理URL必须以http://或socks5://开头。)

英文:

Using https proxies is only supported starting with Go 1.10. From the draft release notes:

> On the client side, an HTTP proxy (most commonly configured by
> ProxyFromEnvironment) can now be specified as an https:// URL, meaning
> that the client connects to the proxy over HTTPS before issuing a
> standard, proxied HTTP request. (Previously, HTTP proxy URLs were
> required to begin with http:// or socks5://.)

答案2

得分: 0

使用Python标准库以及您提供的ProxyHandler,可以通过以下方式解决此问题:

import ssl
import urllib2

# 设置密码和SSL设置
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
ctx.set_ciphers('HIGH:!DH:!aNULL')

# 设置代理设置
proxy = urllib2.ProxyHandler({'https': '<https代理主机>:443', 'http': '<http代理主机>:8080'})
opener = urllib2.build_opener(urllib2.HTTPSHandler(context=ctx), proxy)
urllib2.install_opener(opener)

请注意,上述代码中的<https代理主机><http代理主机>应替换为实际的代理主机地址。

英文:

A possible resolution to this issue using Python standard libraries in addition to the ProxyHandler you have:

import ssl, urllib2
# Set ciphers and ssl settings
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
ctx.set_ciphers(&#39;HIGH:!DH:!aNULL&#39;)
# Set proxy settings
proxy = urllib2.ProxyHandler({&#39;https&#39;:&#39;&lt;https proxy host&gt;:443&#39;, &#39;http&#39;:&#39;&lt;http proxy host&gt;:8080&#39;})
opener = urllib2.build_opener(urllib2.HTTPSHandler(context=ctx), proxy)
urllib2.install_opener(opener)

答案3

得分: 0

最后我不得不自己做客户端。

func http_fetch(req_host string) {
buf := make([]byte, 1024)
conf := &tls.Config {
InsecureSkipVerify: true,
}   
conn, err := tls.Dial("tcp", proxy_host, conf)
if err != nil {
//panic(err)
failure()
return
}   
defer conn.Close()
// SSL连接
if _, err = conn.Write([]byte("CONNECT " + req_host + " HTTP/1.0\r\n\r\n")); err != nil {
// FIXME: 需要调试日志记录器吗?
//panic(err)
failure()
return
}   
// 读取响应
if _, err = conn.Read(buf); err != nil {
//panic(err)
failure()
return
}   
// 发送HTTP GET请求
if _, err = conn.Write([]byte("GET / HTTP/1.0\r\n")); err != nil {
//panic(err)
failure()
return
}   
if _, err = conn.Write([]byte("User-Agent: golang\r\n\r\n")); err != nil {
//panic(err)
failure()
return
}   
// 读取响应
if _, err = conn.Read(buf); err != nil {
//panic(err)
failure()
return
}   
success()
}
英文:

In the end I had to do my own client, essentially.

func http_fetch(req_host string) {
buf := make([]byte, 1024)
conf := &amp;tls.Config {
InsecureSkipVerify: true,
}   
conn, err := tls.Dial(&quot;tcp&quot;, proxy_host, conf)
if err != nil {
//panic(err)
failure()
return
}   
defer conn.Close()
// SSL CONNECT
if _, err = conn.Write([]byte(&quot;CONNECT &quot; + req_host + &quot; HTTP/1.0\r\n\r\n&quot;)); err != nil {
// FIXME: need debug logger?
//panic(err)
failure()
return
}   
// Read response
if _, err = conn.Read(buf); err != nil {
//panic(err)
failure()
return
}   
// Send http GET
if _, err = conn.Write([]byte(&quot;GET / HTTP/1.0\r\n&quot;)); err != nil {
//panic(err)
failure()
return
}   
if _, err = conn.Write([]byte(&quot;User-Agent: golang\r\n\r\n&quot;)); err != nil {
//panic(err)
failure()
return
}   
// Read response
if _, err = conn.Read(buf); err != nil {
//panic(err)
failure()
return
}   
success()
}   

huangapple
  • 本文由 发表于 2017年7月11日 22:25:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/45037328.html
匿名

发表评论

匿名网友

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

确定