Ruby openssl (Net::HTTP verify_hostname, default true)Ruby
错误信息
state=error: certificate verify failed (hostname mismatch)
也可能输出为
- OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 peeraddr=127.0.0.1:8443 state=error: certificate verify failed (hostname mismatch)
完整消息:“SSL_connect returned=1 errno=0 peeraddr=<ip>:<port> state=error: certificate verify failed (hostname mismatch)”。消息中不包含主机名本身;把 URL 与证书对比。
Ruby openssl (Net::HTTP verify_hostname, default true) — OpenSSL::SSL::SSLError from SSL_connect
含义
证书链是受信任的,但 Net::HTTP 所连接的主机名没有出现在证书的主题备用名称中。当前的 Ruby 版本让 OpenSSL 在握手期间检查主机名(verify_hostname),因此问题表现为证书验证失败;较旧的 Ruby 则会在连接后单独抛出“hostname … does not match the server certificate”错误。
原因
证书没有覆盖这个名称
常见SAN 列表中缺少子域名、根域名或已更名的主机。
通过 IP 或内部别名连接
常见配置为使用 IP 地址或容器名称的数据库、Redis 或 API 客户端。
服务器返回了默认证书
偶见不认识所请求名称的代理返回了另一个网站的证书。
修复方法
- 1.
将 SAN 列表与主机对比
消息中不包含这些名称,因此要从证书中把它们打印出来。
bash echo | openssl s_client -connect api.example.com:443 -servername api.example.com 2>/dev/null \ | openssl x509 -noout -ext subjectAltName - 2.
使用证书中的名称,并固定地址
Net::HTTP#ipaddr= 让连接指向指定的 IP,而 SNI 和验证仍使用主机名。
ruby # Connect to a specific address but verify the certificate's name (Net::HTTP#ipaddr=) http = Net::HTTP.new("www.example.com", 443) http.ipaddr = "10.0.0.5" http.use_ssl = true http.get("/health") - 3.
重新签发包含所有在用名称的证书
把缺失的名称添加到 subjectAltName 中。
bash openssl req -new -key server.key -out server.csr -subj "/CN=api.example.com" \ -addext "subjectAltName=DNS:api.example.com,DNS:www.example.com"