麻烦通过mitmproxy传递HTTPS通信

时间:2016-04-23 18:47:02

标签: python-3.x https proxy

我尝试使用mitmproxy和Python 3调试HTTPS连接。想法如下:代理在本地运行,我告诉Python将其用于HTTPS连接; Python必须接受由mitmproxy创建的自签名证书才能生效,如果一切顺利,mitmproxy的控制台将向我显示已解码的请求/响应对。

我能够用Python 3和requests做我想做的事情,但我必须使用标准urllib来做,唉,我失败了。这是代码:

#!/usr/bin/env python3

import urllib.request
import ssl

proxy = urllib.request.ProxyHandler({'https': 'localhost:8080'})
opener = urllib.request.build_opener(proxy)
urllib.request.install_opener(opener)

ssl_ctx = ssl.create_default_context()
ssl_ctx.check_hostname = False
ssl_ctx.verify_mode = ssl.CERT_NONE
#ssl_ctx = ssl._create_unverified_context()

req = urllib.request.Request('https://github.com')

with urllib.request.urlopen(req) as res:
#with urllib.request.urlopen(req, context=ssl_ctx) as res:
    print(res.read().decode('utf8'))

当执行上面的代码时,我得到了一个     ssl.SSLError:[SSL:CERTIFICATE_VERIFY_FAILED]证书验证失败(_ssl.c:645) 错误,表示使用了代理,但其证书未经验证。这正是我期望在这一点上发生的事情。

当我使用注释掉的行来使用ssl_context(以任何方式创建)时,我获取了我请求的页面的内容,但是代理控制台从不显示已解码的请求信息,它保持不变空白。好像使用ssl_context完全绕过了代理。

有人可以帮帮我,告诉我我做错了吗?

编辑:为了确保,我将代理端口更改为8081,现在使用ssl_ctx变量的代码失败了&#39 ;连接被拒绝' (正如预期的那样),并且使用ssl_ctx的代码工作得很好 - 这证明了我的假设,即根本不使用代理。

1 个答案:

答案 0 :(得分:1)

感谢您提出此问题并发布您尝试过的代码。我不确定为什么文档声称不支持通过代理获取HTTPS,因为它确实有效。

除了HTTPSHandler之外,我还创建并安装了ProxyHandler,而不是显式传递SSL上下文。这对我有用(Python 3.5 + mitmproxy):

import urllib.request
import ssl

ssl_ctx = ssl.create_default_context()
ssl_ctx.check_hostname = False
ssl_ctx.verify_mode = ssl.CERT_NONE

ssl_handler = urllib.request.HTTPSHandler(context=ssl_ctx)
proxy_handler = urllib.request.ProxyHandler({'https': 'localhost:8080'})

opener = urllib.request.build_opener(ssl_handler, proxy_handler)
urllib.request.install_opener(opener)


if __name__ == '__main__':
    req = urllib.request.Request('https://...')

    with urllib.request.urlopen(req) as res:
        print(res.read().decode('utf8'))

安装此开启器后,即使在第三方库中,它也被用作使用urllib的所有请求的默认设置 - 这就是我所需要的。

但是,我不确定为什么你的注释掉线不起作用。也许在urlopen中传递上下文会安装一个覆盖自定义的开启者。