Nginx https 协议配置 ssl_protocols 的相关问题

8 篇文章 0 订阅
4 篇文章 0 订阅

1. Nginx https相关配置

官方说明:详细看这里

本文主要针对以下两个主要配置从代码层次进行分析:
协议配置:

Syntax: ssl_protocols [SSLv2] [SSLv3] [TLSv1] [TLSv1.1] [TLSv1.2] [TLSv1.3];
Default:    
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
Context:    http, server

以及加密套件配置

Syntax: ssl_ciphers ciphers;
Default:    
ssl_ciphers HIGH:!aNULL:!MD5;
Context:    http, server

Nginx的虚拟主机配置,使多个网站可以部署在同一个服务器(同一IP地址)对外提供服务。但是在实际测试中发现,虽然两个配置都在server 块内,ssl_protocols 却属于全局配置,而 ssl_ciphers 却针对特定的虚拟主机起作用。

server {
    server_name www.a.com;     
    ssl_ciphers          ECDHE-RSA-AES128-GCM-SHA256;
    ssl_protocols       TLSv1.2;

    # 其他配置略
    }
server {
    server_name www.b.com;     
    ssl_ciphers          ECDHE-RSA-AES256-GCM-SHA384;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;

    # 其他配置略
    }

这里存在一个问题:

  1. 当存在多个server块的时候,即使两个(如上)ssl_protocols 的配置不同,但是浏览器访问(携带SNI信息)www.a.com的时候,仍然可以使用 TLSv1 TLSv1.1 协议,即使没有配置。
  2. 而ssl_ciphers得配置就可以根据域名来区分开来。

    从Nginx的使用文档上来看,两者的配置生效区域相同,却发挥了不同的作用。于是从源码开始分析原因在哪里。

2 Nginx源码分析

Nginx在启动过程中,加载配置文件的时候,对于每个server块的解析,会调用ngx_int_t ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data) 这个函数。

看参数,其中 protocols 就是配置文件中对应的配置项,他是一个 ngx_uint_t 类型,Nginx中关于协议的标志是:ngx_event_openssl.h中定义

#define NGX_SSL_SSLv2    0x0002
#define NGX_SSL_SSLv3    0x0004
#define NGX_SSL_TLSv1    0x0008
#define NGX_SSL_TLSv1_1  0x0010
#define NGX_SSL_TLSv1_2  0x0020

可以看到,每种协议占一位,protocols 的取值就是各个协议做或运算得到的值。比如上文中第一个配置,只有TLSv1.2,那protocols =0x0020【十进制32】,如果是TLSv1 TLSv1.1 TLSv1.2,那就是 protocols = 0x0020 | 0x0010 | 0x0008 = 0x0038【十进制56】。
那么问题来了,造成server间protocols配置混乱的一定是其中某个地方出错了。
那么我们可以先看一下这个protocols的取值是不是对应两个server的取值,就可以看到是不是一开始解析配置文件的时候,就搞错了,于是Nginx源码debug 分析。
得到如下:

(gdb) b ngx_event_openssl.c:ngx_ssl_create
Breakpoint 1 at 0x473b91: file src/event/ngx_event_openssl.c, line 234.
(gdb) r
Breakpoint 1, ngx_ssl_create (ssl=0x9ad548, protocols=56, data=0x9ad540)
    at src/event/ngx_event_openssl.c:234
(gdb) p protocols
$1 = 56
(gdb) c
Continuing.
Breakpoint 1, ngx_ssl_create (ssl=0x9bec60, protocols=32, data=0x9bec58)
    at src/event/ngx_event_openssl.c:234
(gdb) p protocols
$2 = 32

可以看到,没问题,一个32,一个65,没毛病!
那只能继续往下跟踪了。
接下来马上进入Openssl的源码了,看一下nginx在调用Openssl接口的地方代码:

if (!(protocols & NGX_SSL_SSLv2)) {
        SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_SSLv2);
    }
    if (!(protocols & NGX_SSL_SSLv3)) {
        SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_SSLv3);
    }
    if (!(protocols & NGX_SSL_TLSv1)) {
        SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1);
    }
#ifdef SSL_OP_NO_TLSv1_1
    SSL_CTX_clear_options(ssl->ctx, SSL_OP_NO_TLSv1_1);
    if (!(protocols & NGX_SSL_TLSv1_1)) {
        SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1_1);
    }
#endif
#ifdef SSL_OP_NO_TLSv1_2
    SSL_CTX_clear_options(ssl->ctx, SSL_OP_NO_TLSv1_2);
    if (!(protocols & NGX_SSL_TLSv1_2)) {
        SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1_2);
    }
#endif
# define SSL_OP_NO_SSLv2                                 0x01000000L
# define SSL_OP_NO_SSLv3                                 0x02000000L
# define SSL_OP_NO_TLSv1                                 0x04000000L
# define SSL_OP_NO_TLSv1_2                               0x08000000L
# define SSL_OP_NO_TLSv1_1                               0x10000000L

大概意思就是,如果没有定义SSLv2、SSLv3、TLSv1、TLSv1.1、TLSv1.2那么就调用接口SSL_CTX_set_options 进入Openssl来设置协议。

3 Openssl源码分析

版本:Openssl-1.0.2j

源码文件 ssl.h

# define SSL_CTX_set_options(ctx,op) \
        SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,(op),NULL)
# define SSL_CTX_clear_options(ctx,op) \
        SSL_CTX_ctrl((ctx),SSL_CTRL_CLEAR_OPTIONS,(op),NULL)
# define SSL_CTX_get_options(ctx) \
        SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,0,NULL)
# define SSL_set_options(ssl,op) \
        SSL_ctrl((ssl),SSL_CTRL_OPTIONS,(op),NULL)
# define SSL_clear_options(ssl,op) \
        SSL_ctrl((ssl),SSL_CTRL_CLEAR_OPTIONS,(op),NULL)
# define SSL_get_options(ssl) \
        SSL_ctrl((ssl),SSL_CTRL_OPTIONS,0,NULL)

所以要去看 SSL_CTX_ctrl 的源码

源码文件 ssl_lib.c
SSL_CTRL_OPTIONS 的值是32 在下面代码中有个switch(cmd)
关键代码

long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg)
{
...
switch (cmd) {
        ...
        case SSL_CTRL_CLEAR_OPTIONS:
        return (ctx->options &= ~larg);
        ...
        }
}

最后的操作是: ctx->options &= ~larg

再回到Nginx 源码:
对于每种协议,都要调用一次 SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_XXXXX);
也就是 ssl->ctx->options &= ~SSL_OP_NO_XXXXX

先写到这里,稍后继续……

You can overload ssl_ciphers. You can’t overload ssl_protocols
because OpenSSL works this way: it selects the protocol used
before SNI callback (and this behaviour looks more or less natural
beacause the existance of SNI depends on the protocol used, and,
for example, you can’t enable SSLv3 in a SNI-based virtual host).

.

In general, whether or not some SSL feature can be tweaked for
SNI-based virtual hosts depends on two factors:

  • if it’s at all possible;
  • how OpenSSL handles it.

In some cases nginx also tries to provide per-virtualhost support
even for things OpenSSL doesn’t handle natively, e.g., ssl_verify,
ssl_verify_depth, ssl_prefer_server_ciphers.

补充相关链接 :https://mailman.nginx.org/pipermail/nginx/2017-January/052802.html

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
如果您需要在 Nginx 中使用 SSL/TLS,您需要加载 `ngx_http_ssl_module` 模块。要加载此模块,请按照以下步骤进行操作: 1. 检查 Nginx 是否支持 ngx_http_ssl_module 在终端中输入以下命令: ``` nginx -V ``` 如果输出中包含 `--with-http_ssl_module`,则表示 Nginx 已经支持 ngx_http_ssl_module。 2. 编辑 Nginx 配置文件 如果您的 Nginx 配置文件中没有以下内容,请编辑 Nginx 配置文件,并添加以下内容: ``` http { # 其他配置 # 加载 SSL 模块 ssl_prefer_server_ciphers on; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA; ssl_certificate /path/to/ssl_certificate; ssl_certificate_key /path/to/ssl_certificate_key; ssl_session_timeout 1d; ssl_session_cache shared:SSL:50m; ssl_session_tickets off; # 其他配置 } ``` 请将 `/path/to/ssl_certificate` 和 `/path/to/ssl_certificate_key` 替换为您的 SSL 证书和私钥的实际路径。 3. 重新加载 Nginx 配置 在更改 Nginx 配置文件后,需要重新加载 Nginx 配置以使更改生效。您可以使用以下命令重新加载 Nginx 配置: ``` sudo nginx -t && sudo nginx -s reload ``` 现在,您的 Nginx 已经支持 ngx_http_ssl_module 模块了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值