您现在的位置是:首页 > 文章详情

史上最全nginx 安装升级安全配置

日期:2022-11-04点击:264

背景

nginx是常用的代理服务软件,代理层通常是比较靠近用户的,代理层的安全性至关重要,需要我们日常工作中对代理层做好安全相关配置和升级。

这里选择部署openrestry,OpenResty 是以Nginx 为核心的Web 开发平台,可以解析执行Lua 脚本,方便后期基于nginx做web开发或者自研WAF。

1. 下载openrestry

访问官网https://openresty.org/cn/下载最新版本openrestry

cd /root/ wget https://openresty.org/download/openresty-1.21.4.1.tar.gz 

2. nginx 编译安全配置

tar xvf openresty-1.21.4.1.tar.gz cd /root/openresty-1.21.4.1/bundle/nginx-1.21.4/ # - 1.隐藏版本 vim src/core/nginx.h #define NGINX_VERSION "6666" #define NGINX_VER "FW/" NGINX_VERSION ".6" #define NGINX_VAR "FW" # - 2.修改头部 vim src/http/ngx_http_header_filter_module.c # 49 static u_char ngx_http_server_string[] = "Server: FW" CRLF; # - 3.修改错误页响应头部(response header) vim src/http/ngx_http_special_response.c # 22 "<hr><center>FW</center>" CRLF # ... # 29 "<hr><center>FW</center>" CRLF # ... # 36 "<hr><center>FW</center>" CRLF 

3. 增加三方模块

3.1 动态配置upstream的模块nginx_upstream_check_module

检出github代码

cd /root git clone https://github.com/yzprofile/ngx_http_dyups_module.git 

3.2 增加upstream监控检查模块nginx_upstream_check_module

检出github代码

git clone https://github.com/yaoweibin/nginx_upstream_check_module.git 

3.3 增加nginx监控模块nginx-module-vts

检出github代码

https://github.com/vozlt/nginx-module-vts.git 

4. 编译安全nginx

编译之前需要给nginx打补丁,因为nginx-module-vts模块监控需要

切到nginx源码目录 cd /root/openresty-1.21.4.1/bundle/nginx-1.21.4/ 打补丁 patch -p1 < /root/nginx_upstream_check_module/check_1.20.1+.patch 

编译安全nginx

cd /root/openresty-1.21.4.1/ ./configure --prefix=/apps/nginx --with-http_realip_module --with-http_v2_module --with-http_image_filter_module --with-http_iconv_module --with-stream_realip_module --with-stream --with-stream_ssl_module --with-stream_geoip_module --with-http_slice_module --with-http_sub_module --add-module=/root/ngx_http_dyups_module --add-module=/root/nginx_upstream_check_module --with-http_stub_status_module --with-http_geoip_module --with-http_gzip_static_module --add-module=/root/nginx-module-vts make make install 

如果有报如下错,看下是否补丁没有打

/root/nginx-module-vts/src/ngx_http_vhost_traffic_status_display_json.c: In function ‘ngx_http_vhost_traffic_status_display_set_upstream_grou’: /root/nginx-module-vts/src/ngx_http_vhost_traffic_status_display_json.c:604:61: error: ‘ngx_http_upstream_rr_peer_t’ {aka ‘struct ngx_http_upstream_rr_peer_s’} has no member named ‘check_index’; did you mean ‘checked’? if (ngx_http_upstream_check_peer_down(peer->check_index)) { ^~~~~~~~~~~ checked make[2]: *** [objs/Makefile:3330: objs/addon/src/ngx_http_vhost_traffic_status_display_json.o] Error 1 make[2]: Leaving directory '/root/openresty-1.21.4.1/build/nginx-1.21.4' make[1]: *** [Makefile:10: build] Error 2 make[1]: Leaving directory '/root/openresty-1.21.4.1/build/nginx-1.21.4' make: *** [Makefile:9: all] Error 2 [root@localhost.localdomain openrest 

解决办法:

yum install patch cd /root/openresty-1.21.4.1/bundle/nginx-1.21.4/ patch -p1 < /root/nginx_upstream_check_module/check_1.20.1+.patch 

启动nginx

启动: /apps/nginx/nginx/sbin/nginx -c /apps/nginx/nginx/conf/nginx.conf reload: /apps/nginx/nginx/sbin/nginx -s reload -c /apps/nginx/nginx/conf/nginx.conf 

5. nginx升级

在工作中我们会遇到nginx漏洞比如openssl漏洞因而需要升级nginx版本,或者因为nginx某些特性我们需要升级nginx。 升级有两种方式(这里主要聊的是部署在虚机里的,容器重新打个镜像即可): 一是开新虚机直接升级nginx版本,然后把nginx配置copy过来启动,验证没问题后挂载到LB上,逐步替换老的nginx; 二是通过在原来的机器上升级,这里主要谈谈第二种方式。 升级步骤:

前提: 1. 有多台nginx,且从LB上摘掉一台不影响服务 2. pid路径: /data/data/nginx/conf/nginx.pid; 3. conf目录路径独立: /data/data/nginx/conf/ 升级步骤: 1. 从LB上摘除要升级的nginx,观察nginx日志确保没有流量后做下一步动作 2. configure 时指定新的./configure --prefix=/apps/nginx_new 目录 3. 安装完后把nginx_new 目录下的conf 做软连指向/data/data/nginx/conf/ 4. nginx reload : /apps/nginx_new/nginx/sbin/nginx -s reload -c /data/data/nginx/conf//nginx.conf 5. 验证升级后的nginx,如果没有问题然后挂载到LB上,继续重复上述步骤完成其他nginx升级 

6. nginx安全配置

6.1 信息泄露,关闭nginx版本号显示

http{ server_tokens off .... 

6.2 禁用不需要的 Nginx 模块

自动安装的 Nginx 会内置很多模块,并不是所有的模块都需要,对于非必须的模块可以禁用,如 autoindex module ,下面展示如何禁用

# ./configure --without-http_autoindex_module # make # make install 

6.3 控制资源和限制

为了防止对 Nginx 进行潜在的 DOS 攻击,可以为所有客户端设置缓冲区大小限制,配置如下:

## Start: Size Limits & Buffer Overflows ## client_body_buffer_size 1K; client_header_buffer_size 1k; client_max_body_size 1k; large_client_header_buffers 2 1k; ## END: Size Limits & Buffer Overflows ## 

client_body_buffer_size 1k;:(默认8k或16k)这个指令可以指定连接请求实体的缓冲区大小。如果连接请求超过缓存区指定的值,那么这些请求实体的整体或部分将尝试写入一个临时文件。 client_header_buffer_size 1k;:指定客户端请求头部的缓冲区大小。绝大多数情况下一个请求头不会大于1k,不过如果有来自于wap客户端的较大的cookie它可能会大于 1k,Nginx将分配给它一个更大的缓冲区,这个值可以在large_client_header_buffers里面设置。 client_max_body_size 1k;:指令指定允许客户端连接的最大请求实体大小,它出现在请求头部的Content-Length字段。如果请求大于指定的值,客户端将收到一个”Request Entity Too Large” (413)错误。记住,浏览器并不知道怎样显示这个错误。 large_client_header_buffers 2 1k;:指定客户端一些比较大的请求头使用的缓冲区数量和大小。请求字段不能大于一个缓冲区大小,如果客户端发送一个比较大的头,nginx将返回”Request URI too large” (414)。同样,请求的头部最长字段不能大于一个缓冲区,否则服务器将返回”Bad request” (400)。缓冲区只在需求时分开。默认一个缓冲区大小为操作系统中分页文件大小,通常是4k或8k,如果一个连接请求最终将状态转换为keep-alive,它所占用的缓冲区将被释放。

你还需要控制超时来提高服务器性能并与客户端断开连接,配置如下:

## Start: Timeouts ## client_body_timeout 10; client_header_timeout 10; keepalive_timeout 5 5; send_timeout 10; ## End: Timeouts ## 

client_body_timeout 10;:指令指定读取请求实体的超时时间。这里的超时是指一个请求实体没有进入读取步骤,如果连接超过这个时间而客户端没有任何响应,Nginx将返回一个”Request time out” (408)错误。 client_header_timeout 10;:指令指定读取客户端请求头标题的超时时间。这里的超时是指一个请求头没有进入读取步骤,如果连接超过这个时间而客户端没有任何响应,Nginx将返回一个”Request time out” (408)错误。 keepalive_timeout 5 5; :参数的第一个值指定了客户端与服务器长连接的超时时间,超过这个时间,服务器将关闭连接。参数的第二个值(可选)指定了应答头中Keep-Alive: timeout=time的time值,这个值可以使一些浏览器知道什么时候关闭连接,以便服务器不用重复关闭,如果不指定这个参数,nginx不会在应答头中发送Keep-Alive信息。(但这并不是指怎样将一个连接“Keep-Alive”)参数的这两个值可以不相同。 send_timeout 10;:指定了发送给客户端应答后的超时时间,Timeout是指没有进入完整established状态,只完成了两次握手,如果超过这个时间客户端没有任何响应,nginx将关闭连接。

6.4 禁用所有不需要的 HTTP 方法

禁用所有不需要的 HTTP 方法,下面设置意思是只允许 GET、HEAD、POST 方法,过滤掉 DELETE 和 TRACE 等方法。

location / { limit_except GET HEAD POST { deny all; } } 

另一种方法是在 server 块 设置,不过这样是全局设置的,要注意评估影响

if ($request_method !~ ^(GET|HEAD|POST)$ ) { return 444; } 

6.5 防止Host头攻击

添加一个默认server,当host头被修改匹配不到server时会跳到该默认server,该默认server直接返回403错误。

server { listen 80 default; server_name _; location / { return 403; } } 

6.6 配置 SSL 和 cipher suites

Nginx 默认允许使用不安全的旧 SSL 协议,ssl_protocols TLSv1 TLSv1.1 TLSv1.2,建议做如下修改:

ssl_protocols TLSv1.2 TLSv1.3; 

此外要指定 cipher suites ,可以确保在 TLSv1 握手时,使用服务端的配置项,以增强安全性。

ssl_prefer_server_ciphers on 

6.7 防止图片盗链

图片或HTML盗链的意思是有人直接用你网站的图片地址来显示在他的网站上。最终的结果,你需要支付额外的宽带费用。这通常是在论坛和博客。我强烈建议您封锁,并阻止盗链行为。

location /images/ { valid_referers none blocked www.example.com example.com; if ($invalid_referer) { return 403; } } 

例如:重定向并显示指定图片。

valid_referers blocked www.example.com example.com; if ($invalid_referer) { rewrite ^/images/uploads.*.(gif|jpg|jpeg|png)$ http://www.examples.com/banned.jpg last } 

6.8 目录限制

你可以对指定的目录设置访问权限。所有的网站目录应该一一的配置,只允许必须的目录访问权限。

你可以通过IP地址来限制访问目录

location /docs/ { ## block one workstation deny 192.168.1.1; ## allow anyone in 192.168.1.0/24 allow 192.168.1.0/24; ## drop rest of the world deny all; } 

还可以通过密码保护目录 首先创建密码文件并增加“user”用户

mkdir /app/nginx/nginx/conf/.htpasswd/ htpasswd -c /app/nginx/nginx/conf/.htpasswd/passwd user 

编辑nginx.conf,加入需要保护的目录

location ~ /(personal-images/.*|delta/.*) { auth_basic "Restricted"; auth_basic_user_file /usr/local/nginx/conf/.htpasswd/passwd; } 

一旦密码文件已经生成,你也可以用以下的命令来增加允许访问的用户

htpasswd -s /usr/local/nginx/conf/.htpasswd/passwd userName 

6.9 拒绝一些User-Agents

拒绝一些User-Agents 你可以很容易地阻止User-Agents,如扫描器,机器人以及滥用你服务器的垃圾邮件发送者。

## Block download agents ## if ($http_user_agent ~* LWP::Simple|BBBike|wget) { return 403; } ## 

6.10 nginx 去外网IP

nginx如果有漏洞,可能存在远程执行的行为,通过ip下载攻击工具到nginx机器,把nginx机器做跳板做攻击。 通过LB代理nginx,流量先经过LB再到nginx,不要把nginx直接通过外网ip对外。

6.11 配置合理响应头

为了进一步加强 Nginx web 的性能,可以添加几个不同的响应头 X-Frame-Options 可以使用 X-Frame-Options HTTP 响应头指示是否应允许浏览器在 \<frame\>\<iframe\> 中呈现页面。 这样可以防止点击劫持攻击。 配置文件中添加:

add_header X-Frame-Options "SAMEORIGIN"; 

Strict-Transport-Security HTTP Strict Transport Security,简称为 HSTS。它允许一个 HTTPS 网站,要求浏览器总是通过 HTTPS 来访问它,同时会拒绝来自 HTTP 的请求,操作如下:

add_header Strict-Transport-Security "max-age=31536000; includeSubdomains; preload"; 

CSP Content Security Policy (CSP) 保护你的网站避免被使用如 XSS,SQL注入等手段进行攻击,操作如下:

add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always; 

服务用户提供的内容时, 包含 X-Content-Type-Options: nosniff 头选项,配合 Content-Type: 头选项, 来禁用某些浏览器的 content-type 探测.

add_header X-Content-Type-Options nosniff; 

X-XSS-Protection: 表示启用XSS过滤(禁用过滤为X-XSS-Protection: 0),mode=block表示若检查到XSS攻击则停止渲染页面

add_header X-XSS-Protection "1; mode=block"; 

6.12 全站https

将所有 http 跳转至 https

server { listen 80 default_server; listen [::]:80 default_server; server_name .example.com; return 301 https://$host$request_uri; } 

6.13 控制并发连接数

可以通过ngx_http_limit_conn_module模块限制一个IP的并发连接数

http { limit_conn_zone $binary_remote_addr zone=limit1:10m; server { listen 80; server_name example.com; root /apps/project/webapp; index index.html; location / { limit_conn limit 10; } access_log /data/log/nginx/nginx_access.log main; } } 

limit_conn_zone: 设定保存各个键(例如$binary_remote_addr)状态的共享内存空间的参数,zone=空间名字:大小 大小的计算与变量有关,例如$binary_remote_addr变量的大小对于记录IPV4地址是固定的4 bytes,而记录IPV6地址时固定的16 bytes,存储状态在32位平台中占用32或者64 bytes,在64位平台中占用64 bytes。1m的共享内存空间可以保存大约3.2万个32位的状态,1.6万个64位的状态 limit_conn: 指定一块已经设定的共享内存空间(例如name为limit1的空间),以及每个给定键值的最大连接数

上边的例子表示同一IP同一时间只允许10个连接

当有多个limit_conn指令被配置时,所有的连接数限制都会生效

http { limit_conn_zone $binary_remote_addr zone=limit1:10m; limit_conn_zone $server_name zone=limit2:10m; server { listen 80; server_name example.com; root /data/project/webapp; index index.html; location / { limit_conn limit1 10; limit_conn limit2 2000; } } } 

上边的配置不仅会限制单一IP来源的连接数为10,同时也会限制单一虚拟服务器的总连接数为2000

6.14 连接权限控制

实际上nginx的最大连接数是worker_processes乘以worker_connections的总数。

也就是说,下面的这个配置,就是4X65535,一般来说,我们会强调worker_processes设置成和核数相等,worker_connections并没有要求。但是同时这个设置其实给了攻击者空间,攻击者是可以同时发起这么多个连接,把你服务器搞跨。所以,我们应该更合理的配置这两个参数。

user www; worker_processes 4; error_log /data/log/nginx/nginx_error.log crit; pid /data/data/nginx/conf/nginx.pid; events { use epoll; worker_connections 65535; } 

不过,也不是完全没有办法限制,在nginx0.7开始,出了两个新的模块:

HttpLimitReqModul: 限制单个 IP 每秒请求数 HttpLimitZoneModule: 限制单个 IP 的连接数 

这两个模块,要先在http层定义,然后在 location, server, http上下文中作限制,他们用的是限制单ip访问的漏桶算法,也就是说超过定义的限制会报503错误,这样爆发的cc攻击就全部被限制住了。当然,有些时候可能是某个公司同一个ip有几十人一起访问网站,这是有可能被误伤的,做好503报错回调是很有必要的。

先看HttpLimitReqModul:

http { limit_req_zone $binary_remote_addr zone=test_req:10m rate=20r/s; … server { … location /download/ { limit_req zone=test_req burst=5 nodelay; } } } 

上面http层的就是定义,这是一个名为test_req的limit_req_zone空间,用来存储session数据,大小是10M内存,1M大约可以存16000个ip回话,看你访问量有多少就设多少。以$binary_remote_addr为key,这个定义是客户端IP,可以改成$server_name等其他,限制平均每秒的请求为20个,写成20r/m就是每分钟了,也是看你访问量。

下面location层就是应用这个限制了,对应上面的定义,对访问download文件夹的请求,限制每个ip每秒不超过20个请求,漏桶数burst为5,brust的意思就是,如果第1,2,3,4秒请求为19个,第5秒的请求为25个是被允许的。但是如果你第1秒就25个请求,第2秒超过20的请求返回503错误。nodelay,如果不设置该选项,第1秒25个请求时,5个请求放到第2秒执行,设置nodelay,25个请求将在第1秒执行。

就这个限制定义而言,把每个IP限制了请求数,对于海量的cc请求攻击,效果明显,例如限制到1r/s每秒一次请求,那就更明显了,不过也正如开头所说,对于大公司多人统一IP同时访问,难免出现误伤,所以还是得多考虑。

然后再看HttpLimitZoneModule:

http { limit_conn_zone test_zone $binary_remote_addr 10m; server { location /download/ { limit_conn test_zone 10; limit_rate 500k; } } } 

和上面的类似,上面http层就是总定义,这是一个名为test_zone的limit_conn_zone空间,大小也是10M,key还是客户端IP地址,不过这个没有限制次数,改下面定义去了。

下面location层就是真正定义了,因为key定义是客户端ip,所以limit_conn就是一个IP限制了10个连接,如果是$server_name,那就是一个域名10个连接。然后下面limit_rate就是限制一个连接的带宽,如果一个ip两个连接,就是500x2k,这里是10,那就是最多可以有5000K速度给到这个ip了。

6.15 定期升级

nginx本身和nginx使用的三方类库,随着时间的发展和技术的迭代可能会存在重大漏洞,我们负责nginx相关服务的需要定期关注nginx版本更新和相关漏洞,选择性的升级。

原文链接:https://my.oschina.net/helloworldnet/blog/5588202
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章