You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby中基于TCPServer与SSLContext实现SNI证书切换的方法

Ruby实现基于SNI的多证书TLS服务器

要实现根据主机名(SNI)返回不同TLS证书,核心是利用OpenSSL的SNI回调机制,在TLS握手阶段动态为当前连接切换对应证书。以下是完整实现方案:

实现步骤与代码示例

1. 准备证书存储

提前加载所有需要的证书和密钥,用主机名作为索引存到哈希中,避免每次连接重复读取文件:

require 'openssl'
require 'socket'

# 存储主机名到[证书, 密钥]的映射
cert_store = {
  "example.com" => [
    OpenSSL::X509::Certificate.new(File.read("example.com.crt")),
    OpenSSL::PKey::RSA.new(File.read("example.com.key"))
  ],
  "test.com" => [
    OpenSSL::X509::Certificate.new(File.read("test.com.crt")),
    OpenSSL::PKey::RSA.new(File.read("test.com.key"))
  ]
}

2. 配置带SNI回调的SSL上下文

创建基础SSLContext,设置通用TLS参数,关键是添加SNI回调函数,根据客户端发送的主机名切换证书:

context = OpenSSL::SSL::SSLContext.new
context.min_version = :TLS1_2

# 设置SNI回调:握手时根据主机名动态配置证书
context.sni_callback = lambda do |ssl, hostname|
  cert, key = cert_store[hostname]
  if cert && key
    # 为当前连接设置匹配的证书和密钥
    ssl.context.cert = cert
    ssl.context.key = key
  else
    # 无匹配证书时的处理:用默认证书或终止连接
    ssl.context.cert = OpenSSL::X509::Certificate.new(File.read("default.crt"))
    ssl.context.key = OpenSSL::PKey::RSA.new(File.read("default.key"))
    # 可选:直接拒绝连接
    # ssl.alert_write(:handshake_failure)
  end
end

3. 启动SNI-enabled服务器

创建TCP服务器并包装成SSL服务器,循环处理多连接:

host = '0.0.0.0'
port = 443
serv = TCPServer.new(host, port)
secure_server = OpenSSL::SSL::SSLServer.new(serv, context)

puts "SNI TLS server running on #{host}:#{port}"

loop do
  Thread.start(secure_server.accept) do |conn|
    begin
      puts "New connection: #{conn.peeraddr.last}, SNI hostname: #{conn.hostname}"
      # 这里添加业务逻辑,比如HTTP响应
      conn.puts "Welcome to #{conn.hostname}!"
    rescue => e
      puts "Connection error: #{e.message}"
    ensure
      conn.close
    end
  end
end

关键说明

  • SNI回调时机:TLS握手初期,客户端发送SNI扩展(包含目标主机名)时触发回调,此时还未完成证书交换,因此可以动态切换证书。
  • 证书链要求:如果使用中间证书,需要将中间证书合并到主证书文件中(按顺序:主证书在前,中间证书在后),确保客户端能验证完整链。
  • 测试方法:用OpenSSL命令测试SNI功能:
    openssl s_client -connect localhost:443 -servername example.com
    openssl s_client -connect localhost:443 -servername test.com
    

内容的提问来源于stack exchange,提问作者Marek Küthe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 08:18:36