【问题标题】:Python SSLError: VERSION_TOO_LOWPython SSL错误:VERSION_TOO_LOW
【发布时间】:2018-04-02 18:21:54
【问题描述】:

我在使用 urllib 在我的 Debian 服务器上获取一些 Web 内容时遇到了一些问题。我使用以下代码可以毫无问题地获取大多数网站的内容:

import urllib.request as request
url = 'https://www.metal-archives.com/'
req = request.Request(url, headers={'User-Agent': "foobar"})
response = request.urlopen(req)
response.read()

但是,如果网站使用的是较旧的加密协议,urlopen 函数将抛出以下错误:

ssl.SSLError: [SSL: VERSION_TOO_LOW] version too low (_ssl.c:748)

我找到了解决此问题的方法,包括使用 SSL 上下文并将其作为参数传递给 urlopen 函数,因此必须修改之前的代码:

...
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
response = request.urlopen(req, context=context)
...

只要指定的协议与我尝试访问的网站匹配,这将起作用。然而,这似乎不是最好的解决方案,因为:

  1. 如果网站所有者更新了他们的加密方法,代码将停止工作
  2. 上面的代码只适用于这个网站,我必须为我在整个程序中访问的每个网站创建特殊情况,因为每个人都可能使用不同版本的协议。这会导致代码非常混乱
  3. 我发布的第一个解决方案(没有 ssl 上下文的解决方案)奇怪地似乎在我的 ArchLinux 机器上工作,即使它们的所有版本都相同

有人知道适用于每个 TLS 版本的通用解决方案吗?我在这里遗漏了什么吗?

PS:为了完整起见,我会补充说我正在使用 Debian 9、python v3.6.2、openssl v1.1.0f 和 urllib3 v1.22

【问题讨论】:

    标签: python ssl urllib python-3.6


    【解决方案1】:

    最后,我选择将方法调用包装在 try-except 中,这样我就可以使用较旧的 SSL 版本作为备用。最后的代码是这样的:

    url = 'https://www.metal-archives.com'
    req = request.Request(url, headers={"User-Agent": "foobar"})
    try:
        response = request.urlopen(req)
    except (ssl.SSLError, URLError):
        # Try to use the older TLSv1 to see if we can fix the problem
        context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
        response = request.urlopen(req, context=context)
    

    我只在十几个网站上测试过这段代码,到目前为止它似乎工作,但我不确定它是否每次都能工作。此外,这个解决方案似乎效率低下,因为它需要两个 http 请求,这可能非常慢。

    仍然欢迎改进:)

    【讨论】:

      猜你喜欢
      • 2015-03-04
      • 2015-02-05
      • 2017-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-01
      • 2016-08-22
      相关资源
      最近更新 更多