【问题标题】:HTTPS through proxy completely encrypted, including SSL CONNECT通过代理的 HTTPS 完全加密,包括 SSL CONNECT
【发布时间】:2017-12-15 16:19:41
【问题描述】:

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

有谁知道如何通过可用的标准库强制任一技术使用 SSL 到代理?

谢谢。

示例代码如下:

#!/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
}

【问题讨论】:

  • 看起来 Go 版本总是会为 HTTPS (see source) 发出 "CONNECT" - 我对 HTTPS 不太了解,但如果这不是符合标准的行为,您可能会 submit a bug report
  • 我认为它曾经是符合标准的,但我们正在过渡到 HTTPS 代理上的纯 SSL。浏览器支持它,但除了支持它的最新 libcurl 之外,我什么也没找到。
  • 不幸的是,如果它不符合标准,那么支持最多也就是参差不齐。

标签: python ssl go https proxy


【解决方案1】:

除了您拥有的 ProxyHandler 之外,还可以使用 Python 标准库解决此问题:

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('HIGH:!DH:!aNULL')

# Set proxy settings
proxy = urllib2.ProxyHandler({'https':'<https proxy host>:443', 'http':'<http proxy host>:8080'})
opener = urllib2.build_opener(urllib2.HTTPSHandler(context=ctx), proxy)
urllib2.install_opener(opener)

【讨论】:

  • 似乎显示同样的问题。
  • 对于这一行:proxy = urllib2.ProxyHandler({'https':':443', 'http':':8080'}) 你有没有用您自己的代理实现替换
  • 是的。我会仔细检查数据包跟踪,但我认为它仍然可以正常连接。
  • 是的,服务器甚至没有看到 SSL 握手,它立即尝试明文 SSL CONNECT。
  • 是的,连接重置。最后,我不得不直接使用套接字来完成这项工作。 http 库好像不会立即建立 SSL 代理连接。
【解决方案2】:

本质上,我不得不自己做客户。

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 CONNECT
    if _, err = conn.Write([]byte("CONNECT " + req_host + " HTTP/1.0\r\n\r\n")); 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("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
    }   

    // Read response
    if _, err = conn.Read(buf); err != nil {
        //panic(err)
        failure()
        return
    }   
    success()
}   

【讨论】:

    【解决方案3】:

    仅从 Go 1.10 开始支持使用 https 代理。来自draft release notes

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-20
      • 2012-05-18
      • 2011-09-29
      • 1970-01-01
      • 2010-11-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多