21

我正在针对具有自签名证书的私有服务使用 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
4

4 回答 4

17

试试下面的代码:

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

请参阅将 assert_hostname 设置为 False 将禁用 SSL 主机名验证

于 2013-08-05T15:45:52.620 回答
7

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

只需添加cert_reqs='CERT_NONE'参数

import urllib3
http = urllib3.PoolManager(cert_reqs='CERT_NONE')
于 2021-02-16T08:20:03.420 回答
3

我找到了我的问题的答案。实际上,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)
于 2020-06-30T22:08:35.247 回答
2

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

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()返回一个空字符串。

于 2013-08-05T15:34:37.027 回答