5分钟搞懂!Nginx流模块中ssl_reject_handshake指令的正确用法解析

5分钟搞懂!Nginx流模块中ssl_reject_handshake指令的正确用法解析

【免费下载链接】nginx An official read-only mirror of http://hg.nginx.org/nginx/ which is updated hourly. Pull requests on GitHub cannot be accepted and will be automatically closed. The proper way to submit changes to nginx is via the nginx development mailing list, see http://nginx.org/en/docs/contributing_changes.html 【免费下载链接】nginx 项目地址: https://gitcode.com/GitHub_Trending/ng/nginx

你是否还在为Nginx配置SSL时遇到的握手拒绝问题而烦恼?本文将详细解析Nginx流模块中ssl_reject_handshake指令的正确用法,帮助你轻松解决SSL握手相关的安全问题。读完本文后,你将能够:

  • 理解ssl_reject_handshake指令的工作原理
  • 掌握该指令在不同场景下的配置方法
  • 学会排查与该指令相关的常见问题
  • 了解该指令的实现原理及源码位置

什么是ssl_reject_handshake指令?

ssl_reject_handshake是Nginx流模块(Stream Module)中的一个配置指令,用于控制是否拒绝SSL握手。当该指令设置为on时,Nginx会主动拒绝客户端的SSL握手请求,并返回"unrecognized name"(无法识别的名称)告警。

该指令的语法格式如下:

ssl_reject_handshake on | off;

默认值为off,表示不拒绝SSL握手。该指令可以在stream块或server块中配置。

为什么需要使用ssl_reject_handshake?

在实际应用中,我们经常需要在同一IP地址和端口上托管多个SSL服务,这就需要用到SNI(Server Name Indication,服务器名称指示)扩展。SNI允许客户端在SSL握手过程中指定要连接的服务器名称,从而让服务器能够为不同的域名提供不同的SSL证书。

然而,如果客户端不支持SNI或者未正确提供服务器名称,服务器就无法确定应该使用哪个证书,这可能导致安全问题。此时,ssl_reject_handshake指令就派上用场了——它可以帮助我们拒绝那些不支持SNI或提供无效服务器名称的连接请求。

ssl_reject_handshake的工作原理

要理解ssl_reject_handshake的工作原理,我们需要先了解Nginx处理SSL握手的流程。当客户端发起SSL握手时,Nginx会首先检查是否启用了SNI。如果启用了SNI,Nginx会根据客户端提供的服务器名称选择相应的虚拟主机配置。

在这个过程中,ssl_reject_handshake指令的作用是:如果找不到与客户端提供的服务器名称匹配的虚拟主机,Nginx会拒绝此次握手。

从源码实现来看,ssl_reject_handshake的逻辑主要在ngx_stream_ssl_servername函数中实现,该函数位于src/stream/ngx_stream_ssl_module.c文件中。关键代码如下:

done:
    sscf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module);
    if (sscf->reject_handshake) {
        c->ssl->handshake_rejected = 1;
        *ad = SSL_AD_UNRECOGNIZED_NAME;
        return SSL_TLSEXT_ERR_ALERT_FATAL;
    }
    c->ssl->sni_accepted = 1;
    return SSL_TLSEXT_ERR_OK;

从这段代码可以看出,如果reject_handshake被设置为on(即sscf->reject_handshake为真),Nginx会将handshake_rejected标记为1,并返回"unrecognized name"告警,从而拒绝此次握手。

ssl_reject_handshake的配置示例

基本配置示例

下面是一个基本的ssl_reject_handshake配置示例:

stream {
    server {
        listen 443 ssl;
        ssl_certificate /path/to/cert.pem;
        ssl_certificate_key /path/to/key.pem;
        ssl_reject_handshake on;
        
        # 其他配置...
    }
}

在这个示例中,我们在server块中启用了ssl_reject_handshake指令。这意味着,如果客户端请求的服务器名称与该server块不匹配,Nginx将拒绝SSL握手。

结合SNI的多虚拟主机配置

更常见的场景是结合SNI使用多个虚拟主机,如下所示:

stream {
    # 默认服务器,拒绝所有不匹配的SSL握手
    server {
        listen 443 ssl default_server;
        ssl_reject_handshake on;
    }
    
    # 第一个虚拟主机
    server {
        listen 443 ssl;
        ssl_certificate /path/to/cert1.pem;
        ssl_certificate_key /path/to/key1.pem;
        server_name example.com;
        
        # 其他配置...
    }
    
    # 第二个虚拟主机
    server {
        listen 443 ssl;
        ssl_certificate /path/to/cert2.pem;
        ssl_certificate_key /path/to/key2.pem;
        server_name example.org;
        
        # 其他配置...
    }
}

在这个配置中,我们定义了一个默认服务器,并将ssl_reject_handshake设置为on。同时,我们还定义了两个虚拟主机,分别对应不同的域名。当客户端请求的域名与这两个虚拟主机都不匹配时,默认服务器会拒绝SSL握手。

与ssl_preread模块结合使用

ssl_reject_handshake还可以与ssl_preread模块结合使用,实现更复杂的SSL握手控制。例如,我们可以根据客户端请求的服务器名称,动态决定是否拒绝握手:

stream {
    map $ssl_preread_server_name $reject_handshake {
        default on;
        example.com off;
        example.org off;
    }
    
    server {
        listen 443;
        ssl_preread on;
        ssl_reject_handshake $reject_handshake;
        
        # 其他配置...
    }
}

在这个示例中,我们使用map指令根据$ssl_preread_server_name变量(由ssl_preread模块提供)的值来动态设置$reject_handshake变量。当客户端请求的服务器名称是example.comexample.org时,$reject_handshake变量的值为off,即不拒绝握手;对于其他所有服务器名称,$reject_handshake变量的值为on,即拒绝握手。

ssl_reject_handshake的常见问题及解决方案

问题1:配置后所有SSL握手都被拒绝

如果你在配置了ssl_reject_handshake on后发现所有SSL握手都被拒绝,可能是因为你没有正确配置虚拟主机。请确保你至少有一个虚拟主机的server_name与客户端请求的服务器名称匹配,或者没有设置default_server

问题2:配置不生效

如果你发现ssl_reject_handshake配置不生效,可能是因为你没有正确加载Nginx流模块。请检查你的Nginx是否编译了流模块,你可以通过以下命令来验证:

nginx -V 2>&1 | grep -o stream

如果输出中包含stream,说明Nginx编译了流模块。否则,你需要重新编译Nginx,添加--with-stream--with-stream_ssl_module选项。

问题3:与HTTP模块的ssl_reject_handshake混淆

需要注意的是,HTTP模块中也有一个同名指令ssl_reject_handshake,但两者的作用和实现方式有所不同。HTTP模块中的ssl_reject_handshake是在src/http/ngx_http_ssl_module.c文件中实现的,而流模块中的ssl_reject_handshake是在src/stream/ngx_stream_ssl_module.c文件中实现的。

ssl_reject_handshake的源码解析

ssl_reject_handshake指令的实现主要在ngx_stream_ssl_module模块中。该模块的源码位于src/stream/ngx_stream_ssl_module.c文件中。

首先,我们来看一下该指令的定义:

{ ngx_string("ssl_reject_handshake"),
  NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG,
  ngx_conf_set_flag_slot,
  NGX_STREAM_SRV_CONF_OFFSET,
  offsetof(ngx_stream_ssl_srv_conf_t, reject_handshake),
  NULL },

这段代码定义了ssl_reject_handshake指令,指定了它可以在stream块和server块中配置,接受onoff作为参数,并将其值存储在ngx_stream_ssl_srv_conf_t结构体的reject_handshake字段中。

接下来,我们来看一下reject_handshake字段的使用场景,主要在ngx_stream_ssl_servername函数中:

sscf = ngx_stream_get_module_srv_conf(s, ngx_stream_ssl_module);
if (sscf->reject_handshake) {
    c->ssl->handshake_rejected = 1;
    *ad = SSL_AD_UNRECOGNIZED_NAME;
    return SSL_TLSEXT_ERR_ALERT_FATAL;
}

sscf->reject_handshake为真时,Nginx会设置c->ssl->handshake_rejected = 1,并返回SSL_TLSEXT_ERR_ALERT_FATAL,从而拒绝SSL握手。

总结

ssl_reject_handshake是Nginx流模块中一个非常有用的SSL安全配置指令,它可以帮助我们有效控制SSL握手过程,提高服务器的安全性。通过本文的介绍,我们了解了该指令的基本概念、使用场景、配置方法以及实现原理。

在实际应用中,我们应该根据具体需求合理配置ssl_reject_handshake指令,以达到最佳的安全效果。同时,我们还应该关注Nginx的官方文档和源码,以便及时了解该指令的最新变化和最佳实践。

如果你想深入了解Nginx流模块的其他SSL相关指令,可以参考Nginx官方文档或查看src/stream/ngx_stream_ssl_module.c文件中的源码实现。

希望本文能够帮助你更好地理解和使用ssl_reject_handshake指令。如果你有任何问题或建议,欢迎在评论区留言讨论。

【免费下载链接】nginx An official read-only mirror of http://hg.nginx.org/nginx/ which is updated hourly. Pull requests on GitHub cannot be accepted and will be automatically closed. The proper way to submit changes to nginx is via the nginx development mailing list, see http://nginx.org/en/docs/contributing_changes.html 【免费下载链接】nginx 项目地址: https://gitcode.com/GitHub_Trending/ng/nginx

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值