细粒度控制Nginx的HTTP2开与关
Posted OpenResty爱好者
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了细粒度控制Nginx的HTTP2开与关相关的知识,希望对你有一定的参考价值。
引言
nginx官方在早11.6号通告1.9.5-1.15.5的版本都存在两安全漏洞CVE-2018-16843、CVE-2018-16844,可能会导致内存、CPU耗尽,具体与启用了http2功能相关。
修复这两漏洞,无外乎两大途径:一是升级版本至1.15.6/1.14.1;二是关闭http2功能。
诉求
在Nginx里,只需在listen指令后面去除http2配置项即可关闭http2功能;而这一动作是将所有server的http2功能彻底关闭。这有时候并不是想要的效果,最好能针对server级别进行开关控制,更细粒度的把控功能在每个server的使用情况。
大致思路
http2配置项想能在指定server中开启与关闭,大致实现思路如下:
注册配置项http2,允许在server范围使用,设定为flag类型(即选项是on或off)
初始化默认值为on
在协议协商之前把对应的开关项更新,且不影响其它server的开关配置
实现落地
直接参考配置项underscores_in_headers的逻辑实现代码即可,如下:
1.定义配置项http2
{ ngx_string("http2"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_core_srv_conf_t, http2),
NULL },
2.初始化
static void *
ngx_http_core_create_srv_conf(ngx_conf_t *cf)
{
ngx_http_core_srv_conf_t *cscf;
......
cscf->http2 = NGX_CONF_UNSET;
return cscf;
}
3.合并http与server块配置时,设定默认值--1(on 开启)
static char *
ngx_http_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
{
......
ngx_conf_merge_value(conf->http2,
prev->http2, 1);
......
}
4.开关项更新
有了配置项后,究竟在哪个地方可嵌入使用呢?
关键一步:查日志,看http/2协议协商选择发生在哪里
2018/11/14 07:58:55 [ ngx_http_ssl_servername, 870] [debug] 9981#0: *1 SSL server name: "a.com"
2018/11/14 07:58:55 [ ngx_http_ssl_alpn_select, 368] [debug] 9981#0: *1 SSL ALPN supported by client: h2
2018/11/14 07:58:55 [ ngx_http_ssl_alpn_select, 368] [debug] 9981#0: *1 SSL ALPN supported by client: http/1.1
2018/11/14 07:58:55 [ ngx_http_ssl_alpn_select, 395] [debug] 9981#0: *1 SSL ALPN selected: h2
2018/11/14 07:58:55 [ ngx_ssl_handshake, 1234] [debug] 9981#0: *1 SSL_do_handshake: -1
从以上可看出,先是ngx_http_ssl_servername获取到ssl协议带上的主机名,再通过ngx_http_ssl_alpn_select协商选择通讯协议h2或http/1.1。
所以在ngx_http_ssl_servername函数里实现http2开关控制即可影响后续的协议选择,具体如下:
int
ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg)
{
......
hc->ssl_servername = ngx_palloc(c->pool, sizeof(ngx_str_t));
if (hc->ssl_servername == NULL) {
return SSL_TLSEXT_ERR_NOACK;
}
*hc->ssl_servername = host;
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "http2 hc:%d cscf:%d", hc->addr_conf->http2, cscf->http2);
if (hc->addr_conf->http2 && !cscf->http2) {
adcf = ngx_palloc(c->pool, sizeof(ngx_http_addr_conf_t));
if (adcf == NULL) {
return SSL_TLSEXT_ERR_NOACK;
}
ngx_memcpy(adcf, hc->addr_conf, sizeof(ngx_http_addr_conf_t));
adcf->http2 = 0;
hc->addr_conf = adcf;
}
hc->conf_ctx = cscf->ctx;
}
效果查验
重新编译Nginx,对比配置http2开与关的效果:
server {
listen 443 http2;
server_name a.com;
http2 off;
}
2018/11/14 07:55:43 [ ngx_http_ssl_servername, 898] [debug] 9962#0: *1 http2 hc:1 cscf:0
2018/11/14 07:55:43 [ ngx_http_ssl_alpn_select, 368] [debug] 9962#0: *1 SSL ALPN supported by client: h2
2018/11/14 07:55:43 [ ngx_http_ssl_alpn_select, 368] [debug] 9962#0: *1 SSL ALPN supported by client: http/1.1
2018/11/14 07:55:43 [ ngx_http_ssl_alpn_select, 395] [debug] 9962#0: *1 SSL ALPN selected: http/1.1
2018/11/14 07:55:43 [ ngx_ssl_handshake, 1234] [debug] 9962#0: *1 SSL_do_handshake: -1
从debug日志可看到:http2开关在连接上先是开启的,而在server块上是关闭的,经过alpn协商选择最终下降选择了http/1.1协议,即使客户端支持h2协议。
以上即可达到细粒度地控制http2配置的开与关。
往期回顾
以上是关于细粒度控制Nginx的HTTP2开与关的主要内容,如果未能解决你的问题,请参考以下文章