【问题标题】:Ignore certificate validation with urllib3使用 urllib3 忽略证书验证
【发布时间】:2013-08-06 08:46:12
【问题描述】:

我正在针对具有自签名证书的私有服务使用 urllib3。有没有办法让 urllib3 忽略证书错误并提出请求?

import urllib3
c = urllib3.HTTPSConnectionPool('10.0.3.168', port=9001)
c.request('GET', '/')

使用以下内容时:

import urllib3
c = urllib3.HTTPSConnectionPool('10.0.3.168', port=9001, cert_reqs='CERT_NONE')
c.request('GET', '/')

出现以下错误:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3/dist-packages/urllib3/request.py", line 67, in request
    **urlopen_kw)
  File "/usr/lib/python3/dist-packages/urllib3/request.py", line 80, in request_encode_url
    return self.urlopen(method, url, **urlopen_kw)
  File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 415, in urlopen
    body=body, headers=headers)
  File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 267, in _make_request
    conn.request(method, url, **httplib_request_kw)
  File "/usr/lib/python3.3/http/client.py", line 1061, in request
    self._send_request(method, url, body, headers)
  File "/usr/lib/python3.3/http/client.py", line 1099, in _send_request
    self.endheaders(body)
  File "/usr/lib/python3.3/http/client.py", line 1057, in endheaders
    self._send_output(message_body)
  File "/usr/lib/python3.3/http/client.py", line 902, in _send_output
    self.send(msg)
  File "/usr/lib/python3.3/http/client.py", line 840, in send
    self.connect()
  File "/usr/lib/python3/dist-packages/urllib3/connectionpool.py", line 103, in connect
    match_hostname(self.sock.getpeercert(), self.host)
  File "/usr/lib/python3/dist-packages/urllib3/packages/ssl_match_hostname/__init__.py", line 32, in match_hostname
    raise ValueError("empty or no certificate")
ValueError: empty or no certificate

使用cURL 我能够从服务中获得预期的响应

$ curl -k https://10.0.3.168:9001/
Please read the documentation for API endpoints

【问题讨论】:

    标签: python python-3.x urllib3


    【解决方案1】:

    在这个问题中我看到了很多答案,但是恕我直言,太多不必要的信息会导致混淆。

    只需添加cert_reqs='CERT_NONE'参数

    import urllib3
    http = urllib3.PoolManager(cert_reqs='CERT_NONE')
    

    【讨论】:

      【解决方案2】:

      我找到了问题的答案。实际上,urllib3 文档并没有完全解释如何禁止 SSL 证书验证。缺少的是对 ssl.CERT_NONE 的引用。

      我的代码有一个布尔值 ssl_verify,用于指示我是否需要 SSL 验证。现在的代码如下所示:

      import ssl
      import urllib3
      
      #
      #
      #
          if (ssl_verify):
              cert_reqs = ssl.CERT_REQUIRED
          else:
              cert_reqs = ssl.CERT_NONE
              urllib3.disable_warnings()
      
          http = urllib3.PoolManager(cert_reqs = cert_reqs)
      
          auth_url = f'https://{fmc_ip}/api/fmc_platform/v1/auth/generatetoken'
          type = {'Content-Type': 'application/json'}
      
          auth = urllib3.make_headers(basic_auth=f'{username}:{password}')
          headers = { **type, **auth }
      
          resp = http.request('POST',
                          auth_url,
                          headers=headers,
                          timeout=10.0)
      

      【讨论】:

        【解决方案3】:

        试试下面的代码:

        import urllib3
        c = urllib3.HTTPSConnectionPool('10.0.3.168', port=9001, cert_reqs='CERT_NONE',
                                        assert_hostname=False)
        c.request('GET', '/')
        

        Setting assert_hostname to False will disable SSL hostname verification

        【讨论】:

        • 与上述相同的错误。相反,我使用的是 Ubuntu 中提供的旧版本的 urllib3 1.5。即便如此,该提交还没有进入“发布”(上一个版本是 1.6,是 3 个月前,合并是 2 个月前)
        • @MarcoCeppi 我将在下周推出新版本。我们刚刚解决了几个大的未决问题,我需要在发布之前对其进行清理。也就是说,现在欢迎您使用 master 分支,它应该是稳定的。
        • @shazow 谢谢你,不幸的是我被 Ubuntu 档案中的任何东西所束缚,所以这在相当长的一段时间内不会影响我。我已经接受了这个答案作为解决方案,但我最终重新设计了我们的基础架构来解决这个问题。
        • @MarcoCeppi 很抱歉给您带来麻烦。 :) 我会尽力为你加快速度。同样,一旦新版本发布,assert_hostname 也是构造函数 iirc 上的参数。所以你不需要额外的线。
        • 如果有人过来:这也适用于urllib3.PoolManager(cert_reqs='CERT_NONE')
        【解决方案4】:

        尝试以这种方式实例化您的连接池:

        HTTPSConnectionPool(self.host, self.port, cert_reqs=ssl.CERT_NONE)
        

        或者这样:

        HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_NONE')
        

        来源:https://github.com/shazow/urllib3/blob/master/test/with_dummyserver/test_https.py


        编辑(看到您的编辑后):

        看起来远程主机没有发送证书(可能吗?)。 这是引发异常的代码(来自 urllib3):

        def match_hostname(cert, hostname):
            """Verify that *cert* (in decoded format as returned by
        SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 rules
        are mostly followed, but IP addresses are not accepted for *hostname*.
        
        CertificateError is raised on failure. On success, the function
        returns nothing.
        """
            if not cert:
                raise ValueError("empty or no certificate")
        

        所以看起来cert 是空的,这意味着self.sock.getpeercert() 返回了一个空字符串。

        【讨论】:

        • 这真的很奇怪。它确实或应该发回证书。这些服务通过浏览器工作。我的意思是,它是由 ssl-certs Debian 软件包生成的自签名证书。
        猜你喜欢
        • 1970-01-01
        • 2011-11-16
        • 2013-10-16
        • 1970-01-01
        • 2012-08-30
        • 2016-08-04
        • 2016-04-23
        • 2020-10-26
        • 1970-01-01
        相关资源
        最近更新 更多