服务器自动识别客户端并切换证书,其核心通常并不依赖复杂的“识别”逻辑,而是巧妙利用了TLS协议本身的协商机制。

主要有三种实现思路,各有优劣:

案一:基于SNI的证书选择(多域名场景)

Server  Name  Indication  (SNI)  是TLS协议的扩展,允许客户端在握手时告诉服务器它要访问的域名。服务器根据这个信息,就能从众多证书中选出正确的那一个。

      适用场景:同一台服务器上托管了多个不同的网站或服务(例如  `rsa.example.com`  和  `ecc.example.com`),每个域名使用不同的证书。

      实现方式:在Nginx中,为每个域名配置独立的  `server`  块,并在其中指定对应的证书。

      局限性:要求客户端(如浏览器)支持SNI。虽然现代浏览器都支持,但极少数的老旧客户端可能不支持。

方案二:基于TLS协商的自动证书选择(单域名双证书)

这是实现“单域名、双证书”最主流、最优雅的方法。服务器同时提供RSA和ECC(或SM2)两套证书,最终使用哪套由客户端和服务器共同协商决定。

      核心原理:协商过程由密码套件(Cipher  Suite)  驱动。服务器配置的密码套件列表中同时包含  `ECDHE-ECDSA`(对应ECC证书)和  `ECDHE-RSA`(对应RSA证书)。客户端在握手时,会从列表中选择一个自己支持的密码套件。如果客户端支持ECC,它就可能选择  `ECDHE-ECDSA`  套件,从而“触发”服务器使用ECC证书。

      适用场景:希望用一个域名同时服务现代高性能客户端(使用ECC证书)和旧版客户端(使用RSA证书)。

      Nginx配置关键点:

        1.    环境要求:Nginx  ≥  1.11.0,OpenSSL  ≥  1.0.2。

        2.    证书要求:准备两套独立的证书(RSA和ECC),它们的主体(Subject)和所有SAN(Subject  Alternative  Name)必须完全一致。

        3.    配置写法:在同一个  `server`  块中,连续写入两组证书指令。

                ```nginx

                server  {

                        listen  443  ssl;

                        server_name  example.com;


                        #  RSA  证书(建议放在前面)

                        ssl_certificate  /path/to/example.com.rsa.crt;

                        ssl_certificate_key  /path/to/example.com.rsa.key;


                        #  ECC  证书(紧接着RSA配置)

                        ssl_certificate  /path/to/example.com.ecc.crt;

                        ssl_certificate_key  /path/to/example.com.ecc.key;


                        #  协议和密码套件配置

                        ssl_protocols  TLSv1.2  TLSv1.3;

                        ssl_ciphers  ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:...;

                        #  ...  其他配置

                }

                ```

        4.    密码套件:`ssl_ciphers`  配置必须**同时包含**  `ECDHE-ECDSA`  和  `ECDHE-RSA`  开头的套件。

方案三:基于Lua脚本的动态选择(高级定制)

如果前两种方案无法满足需求(例如需要根据客户端IP、TLS版本等其他信息做决策),可以使用Lua脚本在TLS握手阶段进行更细粒度的控制。

      核心原理:在Nginx的  `ssl_certificate_by_lua_block`  阶段,通过Lua脚本分析客户端的  `ClientHello`  消息,获取其支持的签名算法等信息。

      实现方式:例如,脚本检测到客户端支持ECDSA签名算法,则动态加载ECC证书;否则回退到RSA证书。这需要Nginx编译了  `ngx_lua_module`  模块。

方案对比总结

特性      方案一:基于SNI      方案二:TLS协商      方案三:Lua脚本  

实现难度          低      中      高  

灵活性          低(依赖域名)      中(依赖TLS协商)      高(可编程控制)  

性能开销          无      无      极小  

主要优点        配置简单,广泛支持      单域名,自动适配,无额外性能损耗      控制力强,可应对复杂逻辑  

主要缺点          需要多域名或SNI支持      对证书和Nginx版本有要求      配置复杂,需额外模块  

总结与建议

      首选方案二(TLS协商):对于大多数“单域名双证书”(如RSA+ECC或国密+国际)的场景,这是最推荐的方式。它配置标准、性能最优,且对用户完全透明。

      备选方案一(SNI):如果你的双证书分别对应完全不同的域名,这是最直接的选择。

      最后考虑方案三(Lua脚本):只有当你的需求非常特殊,前两种方案都无法满足时,才考虑这种复杂的定制化方案。