跳到主要内容
ecdsa.com
curl (OpenSSL backend)curl

错误信息

curl: (60) SSL certificate problem: self-signed certificate

也可能输出为

  • curl: (60) SSL certificate problem: self signed certificate
  • curl: (60) SSL certificate OpenSSL verify result: self-signed certificate (18)

OpenSSL 3.0 及更高版本打印“self-signed certificate”;OpenSSL 1.1.1 打印“self signed certificate”。较新的 curl 版本(我们测试的是 8.22.0)会写作“SSL certificate OpenSSL verify result: self-signed certificate (18)”。不要把它与“self-signed certificate in certificate chain”混淆,后者存在一条 CA 证书链,并终止于不受信任的根证书。

curl (OpenSSL backend) — CURLE_PEER_FAILED_VERIFICATION, X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT (18)

含义

服务器只出示了一张用自身密钥签名的证书(颁发者与主体相同),而 curl 的信任库中没有这张证书本身。它背后没有可供 curl 查找的 CA,因此验证在深度 0 处就停止了。这对开发服务器和专用设备来说很正常,安装中间证书永远解决不了这个问题。

原因

修复方法

  1. 1.

    核实后,只信任这一张证书

    对于单个内部端点,保存该证书,通过可信渠道(设备的控制台、创建它的管理员)确认其 SHA-256 指纹,再用 --cacert 传入。这样 curl 在这次调用中只接受这张证书,不接受其他任何证书。

    bash
    # Fetch the certificate once, compare its fingerprint out of band, then trust exactly that file
    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
    curl --cacert api.example.com.pem https://api.example.com:8443/
  2. 2.

    开发环境:用本地 CA 签发证书

    使用本地 CA(mkcert、step-ca 或手工创建的根证书),只需信任一个根证书一次,就能为任意数量的开发主机签发证书。这些证书不再是自签名的,因此在安装了该根证书的所有地方,这个错误都会消失。

    bash
    # mkcert creates a local CA, installs it into the system and browser stores,
    # and issues certificates signed by it (no longer self-signed)
    mkcert -install
    mkcert api.example.test localhost 127.0.0.1
  3. 3.

    公网主机:安装公共 CA 签发的证书

    凡是供他人或第三方客户端访问的服务,都应出示由公开受信任的 CA 签发的证书;certbot、lego 或 Caddy 等 ACME 客户端可以自动获取并续期证书。

    bash
    # Public names: get a certificate from a public CA, e.g. with certbot (ACME)
    sudo certbot certonly --nginx -d api.example.com
  4. 4.

    临时诊断:关闭验证以检查服务

    -k 让 curl 跳过证书检查,因此如果返回 200,就说明缺少的只是信任。不要保留它:未经检查就接受的自签名证书随时可能被替换成攻击者的证书,而 curl 不会察觉。

    bash
    # Diagnostic only: confirms the service answers when certificate checks are skipped
    curl -sS -k -o /dev/null -w '%{http_code}\n' https://api.example.com:8443/

相关错误

浏览完整的签名错误库