Nginx配置升级:防御最新网络攻击
Nginx配置升级:防御最新网络攻击
在当今复杂的网络环境中,Nginx作为高性能Web服务器和反向代理,其安全性配置至关重要。通过合理设置HTTP头部字段、限制文件上传大小、使用限流模块以及隐藏版本信息等多种方法,可以有效提升Nginx的安全性能,抵御最新的DDoS攻击、SQL注入和XSS攻击。本文将详细介绍如何全面加固Nginx配置,帮助你构建更坚固的网络安全防线。
基础安全配置
使用主线版本
安全通报里通报的 Nginx 漏洞有时候在 mainline 版本中才会得到修复,因此建议使用主线版本。可以自行添加 NGINX 的 mainline 源。RHEL 及其衍生发行版(CentOS, Oracle Linux, Rocky Linux, AlmaLinux, AnolisOS)可以新建 /etc/yum.repos.d/nginx.repo 文件:
[nginx-mainline]
name=nginx mainline repo
baseurl=https://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=0
enabled=1
module_hotfixes=true
更新到 mainline 版本可能需要先卸载已安装的 Nginx:
dnf config-manager --add-repo /etc/yum.repos.d/nginx.repo
dnf update
nginx -v
nginx version: nginx/1.23.3
隐藏版本信息
隐藏Nginx版本信息可以防止攻击者利用特定版本的漏洞进行攻击。通过修改nginx.conf配置文件实现:
http {
server_tokens off;
}
同时需要修改fastcgi_params和fastcgi.conf文件,将:
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
修改为:
fastcgi_param SERVER_SOFTWARE nginx;
优化配置结构
清晰的配置结构有助于管理和维护。建议将每个子站点的配置文件放在 /etc/nginx/conf.d/ 目录下,使用站点域名或三级域名的第一段命名。泛域名SSL证书配置可以写在 http {} 配置块中,其他配置则应写入独立的 {host}.conf 文件。
防御DDoS攻击
限制请求率
通过limit_req_zone指令限制入站请求率。例如,限制登录页面每两秒只能被访问一次:
limit_req_zone $binary_remote_addr zone=one:10m rate=30r/m;
server {
...
location /login.html {
limit_req zone=one;
...
}
}
限制连接数
使用limit_conn_zone指令限制单个客户端IP的连接数。例如,限制对/store部分的连接数不超过10个:
limit_conn_zone $binary_remote_addr zone=addr:10m;
server {
...
location /store/ {
limit_conn addr 10;
...
}
}
关闭慢连接
通过设置client_body_timeout和client_header_timeout指令来防止Slowloris等慢连接攻击:
server {
client_body_timeout 5s;
client_header_timeout 5s;
...
}
设置IP黑白名单
如果能识别攻击者IP,可以通过deny指令将其屏蔽。例如,拒绝来自特定IP的请求:
location / {
deny 123.123.123.3;
deny 123.123.123.5;
deny 123.123.123.7;
...
}
如果允许访问的IP地址比较固定,可以通过allow和deny指令让网站只接受特定IP地址或IP段的请求:
location / {
allow 192.168.1.0/24;
deny all;
...
}
使用缓存削减流量峰值
通过启用缓存并设置某些缓存参数让Nginx吸收攻击所产生的大部分流量峰值。例如,通过proxy_cache_use_stale指令的updating参数告诉Nginx何时需要更新过期的缓存对象,避免因重复发送更新请求对后端服务器产生压力。
另外,proxy_cache_key指令定义的键通常会包含嵌入的变量,例如默认的键$scheme$proxy_host$request_uri包含了三个变量,如果它包含$query_string变量,那么攻击者可以通过发送随机的query_string值来耗尽缓存,因此,如果没有特别原因,不要在该键中使用$query_string变量。
阻塞恶意请求
配置Nginx阻塞以下类型的请求:
- 以某个特定URL为目标的请求
- User-Agent头中的值不在正常客户端范围之内的请求
- Referer头中的值能够与攻击关联起来的请求
- 其他头中存在能够与攻击关联在一起的值的请求
例如,通过下面的配置阻塞以/foo.php为目标的请求:
location = /foo.php {
deny all;
}
防御SQL注入和XSS攻击
通过在Nginx配置中添加适当的if语句,可以有效防御SQL注入和XSS攻击。以下是一个示例配置:
if ($request_method !~* GET|POST) { return 444; }
#使用444错误代码可以更加减轻服务器负载压力。
#防止SQL注入
if ($query_string ~* (\$|'|--|[+|(%20)]union[+|(%20)]|[+|(%20)]insert[+|(%20)]|[+|(%20)]drop[+|(%20)]|[+|(%20)]truncate[+|(%20)]|[+|(%20)]update[+|(%20)]|[+|(%20)]from[+|(%20)]|[+|(%20)]grant[+|(%20)]|[+|(%20)]exec[+|(%20)]|[+|(%20)]where[+|(%20)]|[+|(%20)]select[+|(%20)]|[+|(%20)]and[+|(%20)]|[+|(%20)]or[+|(%20)]|[+|(%20)]count[+|(%20)]|[+|(%20)]exec[+|(%20)]|[+|(%20)]chr[+|(%20)]|[+|(%20)]mid[+|(%20)]|[+|(%20)]like[+|(%20)]|[+|(%20)]iframe[+|(%20)]|[\<|%3c]script[\>|%3e]|javascript|alert|webscan|dbappsecurity|style|confirm\(|innerhtml|innertext)(.*)$) { return 555; }
if ($uri ~* (/~).*) { return 501; }
if ($uri ~* (\\x.)) { return 501; }
#防止SQL注入
if ($query_string ~* "[;'<>].*") { return 509; }
if ($request_uri ~ " ") { return 509; }
if ($request_uri ~ (\/\.+)) { return 509; }
if ($request_uri ~ (\.+\/)) { return 509; }
#if ($uri ~* (insert|select|delete|update|count|master|truncate|declare|exec|\*|\')(.*)$ ) { return 503; }
#防止SQL注入
if ($request_uri ~* "(cost\()|(concat\()") { return 504; }
if ($request_uri ~* "[+|(%20)]union[+|(%20)]") { return 504; }
if ($request_uri ~* "[+|(%20)]and[+|(%20)]") { return 504; }
if ($request_uri ~* "[+|(%20)]select[+|(%20)]") { return 504; }
if ($request_uri ~* "[+|(%20)]or[+|(%20)]") { return 504; }
if ($request_uri ~* "[+|(%20)]delete[+|(%20)]") { return 504; }
if ($request_uri ~* "[+|(%20)]update[+|(%20)]") { return 504; }
if ($query_string ~ "(<|%3C).*script.*(>|%3E)") { return 505; }
if ($query_string ~ "GLOBALS(=|\[|\%[0-9A-Z]{0,2})") { return 505; }
if ($query_string ~ "_REQUEST(=|\[|\%[0-9A-Z]{0,2})") { return 505; }
限流模块配置
Nginx的限流模块使用漏桶算法来限制请求速率。主要通过limit_req_zone和limit_conn_zone指令来配置。
limit_req_zone配置
Syntax: limit_req zone=name [burst=number] [nodelay];
Default: —
Context: http, server, location
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
- 第一个参数:$binary_remote_addr 表示通过remote_addr这个标识来做限制,“binary_”的目的是缩写内存占用量,是限制同一客户端ip地址。
- 第二个参数:zone=one:10m表示生成一个大小为10M,名字为one的内存区域,用来存储访问的频次信息。
- 第三个参数:rate=1r/s表示允许相同标识的客户端的访问频次,这里限制的是每秒1次,还可以有比如30r/m的。
limit_req配置
limit_req zone=one burst=5 nodelay;
- 第一个参数:zone=one 设置使用哪个配置区域来做限制,与上面limit_req_zone 里的name对应。
- 第二个参数:burst=5,重点说明一下这个配置,burst爆发的意思,这个配置的意思是设置一个大小为5的缓冲区当有大量请求(爆发)过来时,超过了访问频次限制的请求可以先放到这个缓冲区内。
- 第三个参数:nodelay,如果设置,超过访问频次而且缓冲区也满了的时候就会直接返回503,如果没有设置,则所有请求会等待排队。
限制特定UA的访问
limit_req_zone $anti_spider zone=one:10m rate=10r/s;
limit_req zone=one burst=100 nodelay;
if ($http_user_agent ~* "googlebot|bingbot|Feedfetcher-Google") {
set $anti_spider $http_user_agent;
}
其他参数
Syntax: limit_req_log_level info | notice | warn | error;
Default:
limit_req_log_level error;
Context: http, server, location
当服务器由于limit被限速或缓存时,配置写入日志。延迟的记录比拒绝的记录低一个级别。例子:limit_req_log_level notice延迟的的基本是info。
Syntax: limit_req_status code;
Default:
limit_req_status 503;
Context: http, server, location
设置拒绝请求的返回值。值只能设置 400 到 599 之间。
限制单个IP的请求数
这个模块用来限制单个IP的请求数。并非所有的连接都被计数。只有在服务器处理了请求并且已经读取