跳到主要内容
ecdsa.com
Python ssl module (OpenSSL)Python cryptography 库

错误信息

[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate

也可能输出为

  • [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate

Python 会附加 C 源代码位置,例如“(_ssl.c:1082)”。不要与“self-signed certificate in certificate chain”混淆,后者表示 CA 证书链终止于不受信任的根证书。OpenSSL 1.1.1 将其拼写为“self signed”。

Python ssl module (OpenSSL) — ssl.SSLCertVerificationError, X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT (18)

含义

服务器只提供了一张自签名证书(其颁发者就是它自己),而这张证书不在当前上下文受信任的 CA 集合中。没有可以查找的 CA,所以 OpenSSL 在深度 0 处就验证失败了。这常见于开发服务器、设备和新安装的系统;解决办法是有意识地信任这张证书,或者替换它。

原因

修复方法

  1. 1.

    让这个客户端只信任这一张证书

    把服务器自己的证书作为 cafile 加载。主机名和日期检查仍然开启,并且只接受这一张证书。

    python
    import ssl, urllib.request
    
    # Trust exactly this certificate (fetched and fingerprint-checked out of band)
    ctx = ssl.create_default_context(cafile="api.example.com.pem")
    urllib.request.urlopen("https://api.example.com:8443/", context=ctx)
  2. 2.

    获取证书并核对指纹

    在信任该文件之前,把 SHA-256 指纹与设备控制台上显示的值或管理员提供的值进行比对。

    bash
    openssl s_client -connect api.example.com:8443 -servername api.example.com </dev/null 2>/dev/null \
      | openssl x509 -out api.example.com.pem
    openssl x509 -in api.example.com.pem -noout -fingerprint -sha256   # compare with the server's console
  3. 3.

    开发环境:改用本地 CA

    有了本地 CA,你只需信任一个根证书,就能为每台开发主机签发正确签名的证书,任何客户端都不需要为单张证书设置例外。

    bash
    # Development: one local CA, many certificates (mkcert installs the CA for you)
    mkcert -install
    mkcert api.example.test
    export SSL_CERT_FILE="$(mkcert -CAROOT)/rootCA.pem"
  4. 4.

    临时诊断:在测试中关闭验证

    check_hostname = False 和 CERT_NONE 会关闭所有检查并接受任何证书,包括攻击者提供的证书。只用它来确认问题仅在于信任,确认后就删掉。

    python
    # Temporary diagnostic only: proves trust is the sole problem. Never ship this.
    import ssl
    ctx = ssl.create_default_context()
    ctx.check_hostname = False
    ctx.verify_mode = ssl.CERT_NONE

相关错误

浏览完整的签名错误库