如何通过编程方式检测URL的SSL证书是否由Let’s Encrypt签发?
检测域名是否使用Let’s Encrypt证书的Ruby实现方案
你已经找对方向啦!用Net::HTTP获取到的OpenSSL::X509::Certificate对象里,确实藏着判断证书颁发机构的关键信息,只是需要正确提取颁发者字段。我来帮你把这个逻辑补全:
1. 提取证书颁发者信息
cert.issuer方法会返回一个OpenSSL::X509::Name对象,这个对象包含了颁发机构的所有标识信息(比如国家、组织、通用名称等)。你可以通过两种方式判断是否为Let’s Encrypt签发:
方式一:简单匹配关键词
把颁发者信息转成字符串后,检查是否包含"Let's Encrypt"关键词:
issuer_str = cert.issuer.to_s # 示例输出:"/C=US/O=Let's Encrypt/CN=Let's Encrypt Authority R3" is_lets_encrypt = issuer_str.include?("Let's Encrypt")
方式二:精确匹配CA名称
如果需要更严谨的判断,可以提取颁发者的通用名称(CN字段),匹配Let’s Encrypt官方的根/中间CA名称:
# 从issuer中提取CN字段的值 issuer_cn = cert.issuer.to_a.find { |oid, value| oid == "CN" }&.last # Let’s Encrypt常见的有效CA名称列表 lets_encrypt_cas = ["Let's Encrypt Authority R3", "Let's Encrypt Authority X3", "ISRG Root X1"] is_lets_encrypt = lets_encrypt_cas.include?(issuer_cn)
2. 完整的批量检测代码
结合批量处理和异常捕获(避免单个域名失败导致整个脚本中断),完整代码示例如下:
require 'uri' require 'net/http' require 'openssl' def is_lets_encrypt_cert?(domain) begin uri = URI::HTTPS.build(host: domain) # 添加超时和SSL参数,处理各种异常场景 Net::HTTP.start(uri.host, uri.port, use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_NONE, read_timeout: 10) do |http| cert = http.peer_cert # 提取颁发者CN并匹配 issuer_cn = cert.issuer.to_a.find { |oid, value| oid == "CN" }&.last lets_encrypt_cas = ["Let's Encrypt Authority R3", "Let's Encrypt Authority X3", "ISRG Root X1"] lets_encrypt_cas.include?(issuer_cn) end rescue StandardError => e puts "处理#{domain}时出错:#{e.message}" false end end # 示例域名列表,替换成你的实际域名数组 domains = ["example.com", "github.com", "stackoverflow.com"] domains.each do |domain| result = is_lets_encrypt_cert?(domain) puts "#{domain}: #{result ? '使用Let’s Encrypt证书' : '未使用Let’s Encrypt证书'}" end
小提醒
verify_mode: OpenSSL::SSL::VERIFY_NONE是为了绕过证书链验证失败的情况(比如某些域名证书配置有问题但仍能获取到证书),如果你的场景需要严格验证证书有效性,可以去掉这个参数,但要额外处理更多异常。- Let’s Encrypt的CA名称可能会更新,比如现在主流的是R3,未来如果有新的根/中间CA,记得更新
lets_encrypt_cas数组。 - 批量处理时一定要加超时设置,避免某个域名连接超时拖慢整个脚本。
内容的提问来源于stack exchange,提问作者Davi Luis
相关产品推荐
相关产品推荐

