【问题标题】:urllib3 self-signed certificate: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificateurllib3 自签名证书:[SSL: CERTIFICATE_VERIFY_FAILED] 证书验证失败:无法获取本地颁发者证书
【发布时间】:2023-01-13 02:29:22
【问题描述】:

我正在尝试连接到第三方系统,这将使用双方的自签名证书,因为这不会面向公共互联网。

我将 Python 3 与 urllib3 池管理器一起使用。我有证书的副本,私钥和第三方的验证证书。在 curl 中使用这些确认连接有效:

curl https://third_party_url.com/hello -iv --cert ./cert.cert --cacert ./verify.cert   --key ./key.key

但是,当我尝试在代码中使用它时:

client = urllib3.PoolManager(
    cert_file = "./cert.cert",
    key_file="./key.key",
    ca_certs="./verify.cert",
    cert_reqs="CERT_REQUIRED"
)
resp = client.request("GET", "https://third_party_url.com/hello")

出现异常:

    Exception has occurred: SSLError
   [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)

很多类似问题的答案都是关于禁用验证,这绝对不是一个选项。任何投入将不胜感激。

编辑

@Steffen提出的问题的答案

1) 在没有 -cacert 参数的情况下运行时,curl 提供以下输出:

*   Trying 10.10.10.10:443...
* Connected to third_party_url.com (10.10.10.10) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS alert, unknown CA (560):
* SSL certificate problem: unable to get local issuer certificate
* Closing connection 0
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

所以这是同样的问题。这就像 urllib3 不接受加载提供的参数的参数。

2) 在运行openssl x509 -in verify.cert -text 输出没有设置为 CA:true 的基本约束。

输出是:

Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number:
            <SerialNumber>
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = GB, O = me.com, OU = third-party
        Validity
            Not Before: Valid Date
            Not After : Expiry Date
        Subject: C = GB, O = Third Party Company Name, OU = third-party, CN = *third-party.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
            <Modulus>
                Exponent: <Redacted Value>
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
    <Signature Value>
-----BEGIN CERTIFICATE-----
<Certificate Details>
-----END CERTIFICATE-----

【问题讨论】:

  • 您能否检查 1. 当未给出 -cacert 参数时 curl 失败,即给定的 verify.cert 实际上是必不可少的,以及 2. 在获取 verify.cert 的详细信息时(如 openssl x509 -in verify.cert -text),您会看到基本约束设置为 CA:true。
  • 我已经用你问题的答案编辑了我的帖子@SteffenUllrich

标签: python ssl urllib3


【解决方案1】:
    Version: 1 (0x0)
    ...
    Issuer: C = GB, O = me.com, OU = third-party
    ...
    Subject: C = GB, O = Third Party Company Name, OU = third-party, CN = *third-party.com

此证书的颁发者和主题不同。因此,这不是预期作为信任锚的自签名根 CA。

默认情况下,OpenSSL(Python 将其用作 SSL 库)不会将这样的中间证书视为信任锚。仅当显式设置 X509_V_FLAG_PARTIAL_CHAIN 时才会执行此操作,这不是由 Python 执行的,而是由 since a while by curl 执行的。

所以这解释了为什么它在 curl 上成功但在 Python 上失败。

另请参阅Python WWS Library requires entire certificate chain to verify server,了解如何通过在 SSL 上下文中设置适当的选项来处理此问题。

除此之外 - 此证书是非常旧的 X509v2 证书,不支持扩展。现代证书是 X509v3,并且还具有在主题备用名称扩展中有效的域名。像 Chrome 浏览器这样的相关现代软件会抱怨这样的证书。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-20
    • 2021-11-25
    • 2020-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-12
    • 2020-04-06
    相关资源
    最近更新 更多