一、问题描述
因环境内部安全扫描发现CVE-2021-23017、CVE-2022-41741、CVE-2022-41742、CVE-2019-20372漏洞,经分析后,需要将nginx升级到1.23.4版本;
现场环境:centos7.4 1708、nginx 1.20.1
资料:软件下载、360安全、编译参考
二、升级及加固处理
1)版本确认
nginx -V //输出如下
nginx version: nginx/1.20.1
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC)
built with OpenSSL 1.0.2k-fips 26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --add-module=../nginx-rtmp-module-master --with-http_ssl_module --with-stream
2)备份
#如果数据量不大,就整包复制一份
cp -pr ./nginx ./nginx_20230622_1.20.1
3)介质下载及编译安装
wget no-check-certificate https://nginx.org/download/nginx-1.23.4.tar.gz
tar -xzf nginx-1.23.4.tar.gz
#源码包目录
.
├── auto 自动检测系统环境以及编译相关的脚本
│ ├── cc 关于编译器相关的编译选项的检测脚本
│ ├── lib nginx编译所需要的一些库的检测脚本
│ ├── os 与平台相关的一些系统参数与系统调用相关的检测
│ └── types 与数据类型相关的一些辅助脚本
├── conf 存放默认配置文件,在make install后,会拷贝到安装目录中去
├── contrib 存放一些实用工具,如geo配置生成工具(geo2nginx.pl)
├── html 存放默认的网页文件,在make install后,会拷贝到安装目录中去
├── man nginx的man手册
└── src 存放nginx的源代码
├── core nginx的核心源代码,包括常用数据结构的定义,以及nginx初始化运行的核心代码如main函数
├── event 对系统事件处理机制的封装,以及定时器的实现相关代码
│ └── modules 不同事件处理方式的模块化,如select、poll、epoll、kqueue等
├── http nginx作为http服务器相关的代码
│ └── modules 包含http的各种功能模块
├── mail nginx作为邮件代理服务器相关的代码
├── misc 一些辅助代码,测试c++头的兼容性,以及对google_perftools的支持
└── os 主要是对各种不同体系统结构所提供的系统函数的封装,对外提供统一的系统调用接口
cd nginx-1.23.4
./configure --prefix=/usr/local/nginx --add-module=/data/spms/nginx-rtmp-module-master --with-http_ssl_module --with-stream //输出如下
……
checking for getaddrinfo() ... found
configuring additional modules
adding module in /data/spms/nginx-rtmp-module-master
+ ngx_rtmp_module was configured
checking for PCRE2 library ... not found
checking for PCRE library ... found
checking for PCRE JIT support ... found
checking for OpenSSL library ... found
checking for zlib library ... found
creating objs/Makefile
Configuration summary
+ using system PCRE library
+ using system OpenSSL library
+ using system zlib library
nginx path prefix: "/usr/local/nginx"
nginx binary file: "/usr/local/nginx/sbin/nginx"
nginx modules path: "/usr/local/nginx/modules"
nginx configuration prefix: "/usr/local/nginx/conf"
nginx configuration file: "/usr/local/nginx/conf/nginx.conf"
nginx pid file: "/usr/local/nginx/logs/nginx.pid"
nginx error log file: "/usr/local/nginx/logs/error.log"
nginx http access log file: "/usr/local/nginx/logs/access.log"
nginx http client request body temporary files: "client_body_temp"
nginx http proxy temporary files: "proxy_temp"
nginx http fastcgi temporary files: "fastcgi_temp"
nginx http uwsgi temporary files: "uwsgi_temp"
nginx http scgi temporary files: "scgi_temp"
#编译
make -j4 //输出如下
……
objs/addon/nginx-rtmp-module-master/ngx_rtmp_proxy_protocol.o \
objs/addon/hls/ngx_rtmp_hls_module.o \
objs/addon/dash/ngx_rtmp_dash_module.o \
objs/addon/hls/ngx_rtmp_mpegts.o \
objs/addon/dash/ngx_rtmp_mp4.o \
objs/addon/nginx-rtmp-module-master/ngx_rtmp_stat_module.o \
objs/addon/nginx-rtmp-module-master/ngx_rtmp_control_module.o \
objs/ngx_modules.o \
-ldl -lpthread -lcrypt -lpcre -lssl -lcrypto -ldl -lpthread -lz \
-Wl,-E
make[1]: Leaving directory `/home/ygcg/nginx-1.23.4'
#验证
cd objs/
ls //如下所示
addon Makefile nginx.8 ngx_auto_headers.h ngx_modules.o
autoconf.err nginx ngx_auto_config.h ngx_modules.c src
4)热升级替换及验证
mv ./sbin/nginx ./sbin/nginx_1.20.1
cp -pr /home/ygcg/nginx-1.23.4/objs/nginx ./sbin/
#确认nginx.pid位置
find ./ -name nginx.pid
./logs/nginx.pid
cat ./logs/nginx.pid
#热升级
kill -USR2 `cat /usr/local/nginx/logs/nginx.pid `
ll /usr/local/nginx/logs/nginx.pid.oldbin //输出如下
-rw-r--r-- 1 ygcg root 5 Sep 14 2022 /usr/local/nginx/logs/nginx.pid.oldbin
kill -QUIT `cat /usr/local/nginx/logs/nginx.pid.oldbin` //优雅退出
ln -s /usr/local/nginx/sbin/nginx /bin/ #绝对路径
nginx -V #验证
nginx version: nginx/1.23.4
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC)
built with OpenSSL 1.0.2k-fips 26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/usr/local/nginx --add-module=/data/spms/nginx-rtmp-module-master --with-http_ssl_module --with-stream
三、附录:
3.1、NGINX 常见模块
我们在nginx预编译过程中,可使用参数–add-module=PATH指定第三方模块路径来添加模块,我们常见的有:
1、nginx-module-vts 模块实现流量监控
git clone https://github.com/vozlt/nginx-module-vts.git
./configure --prefix=/apps/nginx --add-module=/usr/local/src/nginx-module-vts
配置参考:
http {
…
vhost_traffic_status_zone; #先填入模块
…
server {
…
location /status {
vhost_traffic_status_display; #开启模块
vhost_traffic_status_display_format html; #模块的页面
} ##编译新模块需要重启nginx才能访问测试,不支持reload,重启之后就可浏览器访问:http://<nginx_ip>/status
2、echo模块
git clone https://github.com.cnpmjs.org/openresty/echo-nginx-module.git
/configure
–prefix=/usr/local/nginx
–user=nginx --group=nginx
–with-http_ssl_module
–with-http_v2_module
–with-http_realip_module
–with-http_stub_status_module
–with-http_gzip_static_module
–with-pcre
–with-stream
–with-stream_ssl_module
–with-stream_realip_module
–with-http_perl_module
–add-module=/usr/local/modules/echo-nginx-module
2、开启目录索引
语法: autoindex on | off;
默认: autoindex off;
位置: http, server, location
3.格式化文件大小
语法: autoindex_exact_size on | off;
默认: autoindex_exact_size on;
位置: http, server, location
4.输出的格式
语法: autoindex_format html | xml | json | jsonp;
默认: autoindex_format html;
位置: http, server, location
5.使用时区
语法: autoindex_localtime on | off;
默认: autoindex_localtime off;
位置: http, server, location
6、http_auth_basic_module HTTP基本认证
用途:提供HTTP基本认证功能。
内置模块:是。
默认启用:是。如果需要禁用,编译Nginx时使用–without-http_auth_basic_module。
作用域:http, server, location, limit_except
server {
listen 80;
server_name test.com;
auth_basic "登录认证";
auth_basic_user_file /etc/nginx-htpasswd;
root /mnt/html/www;
index index.html;
}
7、http_stub_status_module 状态信息
用途:该模块可以提供 Nginx 的状态信息。
内置模块:是。
默认启用:否。如果需要启用,编译Nginx时使用–with-http_stub_status_module。
作用域:server, location
该模块仅有stub_status这一个指令。
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
8、http_gzip_module 压缩资源
用途:用于支持gzip on等指令,用来减轻服务器的带宽问题,经过gzip压缩后的页面大小可以变为原来的30%甚至更小。
内置模块:是。
默认启用:是。如果需要禁用,编译Nginx时使用–without-http_gzip_module。
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
#gzip_http_version 1.0;
gzip_comp_level 2;
gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
gzip_vary off;
gzip_disable “MSIE [1-6].”;
9、http_gzip_static_module 支持.gz资源
用途:允许发送以.gz作为文件扩展名的预压缩文件,以替代发送普通文件。
内置模块:是。
默认启用:否。如果需要启用,编译Nginx时使用–with-http_gzip_static_module。
gzip_static on;
10、http_sub_module 字符串替换
用途:该模块用于实现响应内容固定字符串替换。
内置模块:是。
默认启用:否。如果需要启用,编译Nginx时使用–with-http_sub_module。
作用域:http, server, location
该模块不支持正则替换,灵活性不够。支持正则匹配替换的第三方模块:
1、ngx_http_substitutions_filter_module:https://github.com/yaoweibin/ngx_http_substitutions_filter_module
2、replace-filter-nginx-module:https://github.com/agentzh/replace-filter-nginx-module
location / {
sub_filter ‘<a href="http://127.0.0.1:8080/’ '<a href="https://KaTeX parse error: Double superscript at position 36: …er 'nginx.com' '̲baidu.com'; …HOME/nginx_mod_h264_streaming-2.2.7 --sbin-path=/usr/local/sbin --with-debug
\
更多参看官网或外部博客,配置项模块参看nginx模块
3.2、nginx配置文件变量
1、日志格式变量
$remote_addr # 记录客户端IP地址
$remote_user # 记录客户端用户名
$time_local # 记录通用的本地时间
$time_iso8601 # 记录ISO8601标准格式下的本地时间
$request # 记录请求的方法以及请求的http协议
$status # 记录请求状态码(用于定位错误信息)
$body_bytes_sent # 发送给客户端的资源字节数,不包括响应头的大小
KaTeX parse error: Expected 'EOF', got '#' at position 12: bytes_sent #̲ 发送给客户端的总字节数msec # 日志写入时间。单位为秒,精度是毫秒。
$http_referer # 记录从哪个页面链接访问过来的
$http_user_agent # 记录客户端浏览器相关信息
$http_x_forwarded_for #记录客户端IP地址
$request_length # 请求的长度(包括请求行,请求头和请求正文)。
$request_time # 请求花费的时间,单位为秒,精度毫秒注:如果Nginx位于负载均衡器,nginx反向代理之后,web服务器无法直接获取到客 户端真实的IP地址。
$remote_addr获取的是反向代理的IP地址。 反向代理服务器在转发请求的http头信息中,
增加X-Forwarded-For信息,用来记录客户端IP地址和客户端请求的服务器地址
#日志格式定义示例
http {
log_format access_log_format '$remote_addr - $remote_user [$time_local]
"$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"'
'$server_name:$server_port';
}
#Nginx 的默认访问日志记录内容相对比较单一,不方便后期做日志统计分析,生产环境中通常将nginx日志转换为json日志,然后配合使用ELK做日志收集,统计和分析。参考链接:http://json.cn/
http {
log_format access_json '{"@timestamp":"$time_iso8601",'
'"host":"$server_addr",'
'"clientip":"$remote_addr",'
'"size":$body_bytes_sent,'
'"responsetime":$request_time,' #总的处理时间
'"upstreamtime":"$upstream_response_time",' #后端应用服务器处理时间
'"upstreamhost":"$upstream_addr",'
'"http_host":"$host",'
'"uri":"$uri",'
'"xff":"$http_x_forwarded_for",'
'"referer":"$http_referer",'
'"tcp_xff":"$proxy_protocol_addr",'
'"http_user_agent":"$http_user_agent",'
'"status":"$status"}';
access_log /usr/local/nginx/logs/access_json.log access_json;
}
#日志过滤
#比如请求favicon.ico时,不记录日志;是浏览器收藏网址时显示的图标,当客户端使用浏览器问页面时,浏览器会自己主动发起请求获取页面的favicon.ico文件,但是当浏览器请求的favicon.ico文件不存在时,服务器会记录404日志,而且浏览器也会显示404报错
location /favicon.ico {
log_not_found off;
access_log off;
return 200;
}
#当有人访问gif、png等资源时,将日志丢入空
location ~* .*\.(gif|jpg|png|css|js)$ {
access_log /dev/null;
}
2、Nginx内置变量
$remote_addr;
#存放了客户端的地址,注意是客户端的公网IP
$args;
#变量中存放了URL中的所有参数,例如:http://www.ehuo.org/main/index.do?
id=20190221&partner=search
#返回结果为: id=20190221&partner=search
$host;
#存放了请求的host名称
echo $limit_rate;
#如果nginx服务器使用limit_rate配置了显示网络速率,则会显示,如果没有设置, 则显示0
$remote_port;
#客户端请求Nginx服务器时随机打开的端口,这是每个客户端自己的端口
$remote_user;
#已经经过Auth Basic Module验证的用户名
$request_body_file;
#做反向代理时发给后端服务器的本地资源的名称
$request_method;
#请求资源的方式,GET/PUT/DELETE等
$request_filename;
#当前请求的资源文件的磁盘路径,由root或alias指令与URI请求生成的文件绝对路径,
如:/apps/nginx/html/main/index.html
KaTeX parse error: Expected 'EOF', got '#' at position 14: request_uri; #̲包含请求参数的原始URI,不包…document_uri?$args,例如:/main/index.do?
id=20190221&partner=search
$scheme;
#请求的协议,例如:http,https,ftp等
$server_protocol;
#保存了客户端请求资源使用的协议的版本,例如:HTTP/1.0,HTTP/1.1,HTTP/2.0等
$server_addr;
#保存了服务器的IP地址
$server_name;
#请求的服务器的主机名
$server_port;
#请求的服务器的端口号
$http_user_agent;
#客户端浏览器的详细信息
$http_cookie;
#客户端的所有cookie信息
$cookie_
#name为任意请求报文首部字部cookie的key名
$http_
#name为任意请求报文首部字段,表示记录请求报文的首部字段,ame的对应的首部字段名需要为小写,如果有横线需要替换为下划线
arbitrary request header field; the last part of a variable name is the field
name converted to lower case with dashes replaced by underscores #用下划线代替横线
3.3、Nginx https 流程图
https://nginx.org/en/docs/http/ngx_http_ssl_module.html
To reduce the processor load it is recommended to
set the number of worker processes equal to the number of processors,
enable keep-alive connections,
enable the shared session cache,
disable the built-in session cache,
and possibly increase the session lifetime (by default, 5 minutes):
worker_processes auto;
http {
...
server {
listen 443 ssl;
keepalive_timeout 70;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers AES128-SHA:AES256-SHA:RC4-SHA:DES-CBC3-SHA:RC4-MD5;
ssl_certificate /usr/local/nginx/conf/cert.pem;
ssl_certificate_key /usr/local/nginx/conf/cert.key;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
...
}
#自签名CA证书
openssl req -newkey rsa:4096 -nodes -sha256 -keyout ca.key -x509 -days 3650 -out ca.crt
#自制key和csr文件
openssl req -newkey rsa:4096 -nodes -sha256 -keyout server.key -out server.csr
#自签发crt证书
openssl x509 -req -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt
#查看证书内容
openssl x509 -in server.crt -noout -text
3.4、http强制https
server {
listen 443 ssl;
server_name www.ehuo.org;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
location / {
if ( $scheme = http ) {
rewrite ^/(.*)$ https://www.ehuo.org/$1 redirect; #主要实现
}
3.5、防盗链
#配置完成 后可使用curl -e参数指定refer测试
vim /usr/local/nginx/conf/conf.d/pc.conf //如下所示
server {
index index.html;
valid_referers none blocked server_names *.blue.com *.blue.org
~\.google\. ~\.baidu\. ~\.bing\. ~\.so\. ; #定义有效的referer
if ($invalid_referer) { #假如是使用其他的无效的referer访问
return 403 "Forbidden Access"; #返回状态码403
#return 302 http:/blue.com/test.jpg;
#rewrite ^(.*)$ /daolian.jpg break;#或者返回错误图片
}
......
}
#语法说明
Syntax: valid_referers none | blocked | server_names | string ...;
Default: —
Context: server, location
none:#请求报文首部没有referer首部,比如用户直接在浏览器输入域名访问web网站,就没有referer信
息。
blocked:#请求报文有referer首部,但无有效值,比如为空。
server_names:#referer首部中包含本主机名及即nginx 监听的server_name。
arbitrary_string:#自定义指定字符串,但可使用*作通配符。示例: *.ehuo.org www.ehuo.*
regular expression:#被指定的正则表达式模式匹配到的字符串,要使用~开头,例如:
~.*\.ehuo\.com