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

错误信息

curl: (60) SSL: no alternative certificate subject name matches target hostname 'api.example.com'

也可能输出为

  • curl: (60) SSL: no alternative certificate subject name matches target host name 'api.example.com'

curl 8.x 打印“target hostname”;curl 7.x 打印的是“target host name”。引号中的主机就是 URL 中写的内容。非常旧的 curl 版本(7.62.0 之前)对这项检查使用退出码 51。

curl (OpenSSL backend) — CURLE_PEER_FAILED_VERIFICATION, hostname check in lib/vtls/openssl.c

含义

证书链是受信任的,但证书主题备用名称(SAN)扩展中的 DNS 名称(或 IP 地址)没有一个与 URL 中的主机匹配。curl 只拿 URL 的主机与 SAN 条目比较;只要存在 SAN 扩展,主体的通用名称就会被忽略。末尾引号中的名称就是要求 curl 访问的主机。

原因

修复方法

  1. 1.

    将 SAN 列表与 URL 比对

    打印服务器所提供证书的 subjectAltName 扩展。修复方法有两种:换用列出该名称的证书,或者让 URL 使用已列出的名称之一。

    bash
    # Names the served certificate actually covers
    echo | openssl s_client -connect api.example.com:443 -servername api.example.com 2>/dev/null \
      | openssl x509 -noout -subject -ext subjectAltName
  2. 2.

    重新签发证书,包含所有正在使用的名称

    把所有主机名(如果客户端通过 IP 连接,还有 IP 地址)都申请为 SAN 条目。只把名称放进通用名称,对当前任何客户端都不起作用。

    bash
    # ACME: list every name the certificate must cover
    sudo certbot certonly --nginx -d example.com -d www.example.com -d api.example.com
    
    # Private CA: put all names into subjectAltName (CN is ignored for matching)
    openssl req -new -key server.key -out server.csr -subj "/CN=api.example.com" \
      -addext "subjectAltName=DNS:api.example.com,DNS:www.example.com,IP:10.0.0.5"
  3. 3.

    保留名称,只改地址

    当你必须访问某个特定地址(负载均衡器节点、隧道、预发布环境的 IP)时,--resolve 或 --connect-to 会保留 URL 中的主机,因此 SNI 和主机名检查仍然使用证书上的名称。

    bash
    # Keep the certificate's name in the URL and steer the connection to another address
    curl --resolve api.example.com:443:10.0.0.5 https://api.example.com/
    curl --connect-to api.example.com:443:lb-internal.example.net:443 https://api.example.com/
  4. 4.

    服务器所有者:检查 SNI 路由

    如果带 SNI 和不带 SNI 的请求得到的证书不同,就为该名称添加一个 server 块(或 Ingress 规则),并确保客户端访问真实主机名时拿到的不是默认证书。

    bash
    # Compare what the server returns with and without SNI
    openssl s_client -connect 10.0.0.5:443 -servername api.example.com </dev/null 2>/dev/null | openssl x509 -noout -subject
    openssl s_client -connect 10.0.0.5:443 -noservername </dev/null 2>/dev/null | openssl x509 -noout -subject

相关错误

浏览完整的签名错误库