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

基于Boost ASIO SSL实现单IP多HTTPS站点的SNI证书适配方案咨询

实现思路

Boost.Asio的SSL组件本质是对OpenSSL原生接口的封装,没有直接暴露SNI相关接口,但完全可以通过调用OpenSSL原生API实现SNI多证书匹配,不需要依赖Boost官方的封装支持。

具体修改步骤

1. 新增依赖与成员变量

首先引入OpenSSL原生头文件,替换原有单SSL上下文结构为多上下文映射:

#include <openssl/ssl.h>
#include <unordered_map>

// 类私有成员修改,删除原有单一ctx_变量,替换为:
std::shared_ptr<boost::asio::ssl::context> default_ctx_;
std::unordered_map<std::string, std::shared_ptr<boost::asio::ssl::context>> domain_ctx_map_;

2. 实现SNI回调函数

在类中新增静态C风格回调,用于在TLS握手阶段获取客户端发送的SNI域名,切换对应SSL上下文:

static int sni_callback(SSL *ssl, int *ad, void *arg) {
    if (!ssl) return SSL_TLSEXT_ERR_NOACK;
    const char* server_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
    if (!server_name) return SSL_TLSEXT_ERR_OK; // 无SNI用默认证书

    auto* server_inst = static_cast<httpTLS_server_*>(arg);
    auto iter = server_inst->domain_ctx_map_.find(server_name);
    if (iter != server_inst->domain_ctx_map_.end()) {
        // 匹配到对应域名证书,切换上下文
        SSL_set_SSL_CTX(ssl, iter->second->native_handle());
    }
    return SSL_TLSEXT_ERR_OK;
}

3. 新增多证书加载接口

新增添加域名证书的方法,同时兼容原有单证书逻辑:

// 新增公有方法:添加域名对应证书,domain传*表示默认证书
template<typename F>
void add_domain_cert(const std::string& domain, F&& pwd_cb, 
    std::string certificate_chain_file, std::string private_key_file, std::string tmp_dh_file = "") {
    auto ctx = std::make_shared<boost::asio::ssl::context>(boost::asio::ssl::context::tls_server);
    unsigned long ssl_options = boost::asio::ssl::context::default_workarounds
        | boost::asio::ssl::context::no_sslv2
        | boost::asio::ssl::context::no_sslv3
        | boost::asio::ssl::context::no_tlsv1
        | boost::asio::ssl::context::single_dh_use;
    ctx->set_options(ssl_options);
    ctx->set_password_callback(std::forward<F>(pwd_cb));
    ctx->use_certificate_chain_file(std::move(certificate_chain_file));
    ctx->use_private_key_file(std::move(private_key_file), boost::asio::ssl::context::pem);
    if (!tmp_dh_file.empty()) {
        ctx->use_tmp_dh_file(std::move(tmp_dh_file));
    }
    if (domain == "*") {
        default_ctx_ = ctx;
        // 给默认上下文注册SNI回调
        SSL_CTX_set_tlsext_servername_callback(default_ctx_->native_handle(), sni_callback);
        SSL_CTX_set_app_data(default_ctx_->native_handle(), this);
    } else {
        domain_ctx_map_[domain] = ctx;
    }
}

// 原有init_ssl_context可直接兼容:
template<typename F>
void init_ssl_context(bool ssl_enable_v3, F&& f, std::string certificate_chain_file,
    std::string private_key_file, std::string tmp_dh_file) {
    add_domain_cert("*", std::forward<F>(f), 
        std::move(certificate_chain_file), std::move(private_key_file), std::move(tmp_dh_file));
}

4. 修改连接初始化逻辑

修改start_accept方法中传入SSL上下文的部分,替换为默认上下文即可:

auto new_conn = std::make_shared<connection_ssl<Socket_ssl>>(
    io_service_pool_.get_io_service(), max_req_buf_size_, keep_alive_timeout_, https_handler_, static_dir_, 
    upload_check_?&upload_check_ : nullptr, *default_ctx_
);
注意事项
  • 要求OpenSSL版本 >= 1.0.1,已默认支持SNI扩展
  • 如需支持泛域名证书,可将精确匹配逻辑改为后缀匹配,例如将*.example.com的证书存储在key为.example.com的映射项中,拿到SNI后判断后缀匹配即可
  • 所有SSL上下文的密码回调、DH参数等配置可根据域名单独调整,无需统一

内容的提问来源于stack exchange,提问作者Neo Chen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 22:18:02