我尝试使用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
的代码工作得很好 - 这证明了我的假设,即根本不使用代理。
答案 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
中传递上下文会安装一个覆盖自定义的开启者。