openresty配置
确保已经正确整合openresty和modsecurity
完整配置如下,增加了白名单和黑名单已经限制请求次数
load_module modules/ngx_http_modsecurity_module.so;
#user nobody;
worker_processes 4;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
underscores_in_headers on;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
gzip on; # 启用 Gzip 压缩
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
gzip_vary on; # 向响应头添加 `Vary: Accept-Encoding`,以确保代理缓存的正确性
gzip_min_length 1024; # 设置压缩的最小文件大小,较小的文件可能不压缩
gzip_proxied any; # 启用代理后端的压缩响应
gzip_comp_level 5; # 设置压缩级别,范围是1-9,数值越大压缩比越高,但CPU消耗也更大
geo $whitelist {
default 0; # 默认不是白名单中的IP
#10.0.0.0/8 1; # 白名单IP段
#192.168.1.100 1; # 白名单单个IP
}
geo $blacklist {
default 0; # 默认不是黑名单中的IP
#192.168.1.0/24 1; # 黑名单IP段
#203.0.113.50 1; # 黑名单单个IP
}
# 将白名单和黑名单组合起来判断
map $whitelist$blacklist $access {
"10" 0; # 在白名单中时,即使在黑名单中,仍然允许访问
"11" 0; # 在白名单中时,即使在黑名单中,仍然允许访问
"01" 1; # 不在白名单中,但在黑名单中,拒绝访问
"00" 0; # 不在白名单或黑名单中,允许访问(默认行为,可以改为1表示拒绝)
}
# 调整为50MB的限流区,允许每秒10个请求,突发请求允许20个根据IP地址的数量自行调整限流区
limit_req_zone $binary_remote_addr zone=req_zone:50m rate=10r/s;
# 定义一个连接限制区,大小为10MB,最大连接数为10个
limit_conn_zone $binary_remote_addr zone=conn_zone:50m;
log_format custom '$remote_addr $host $proxy_add_x_forwarded_for - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /app/openresty/nginx/logs/access.log custom;
server {
listen 8080;
server_name 0.0.0.0;
charset utf-8;
# 在特定位置启用 ModSecurity
modsecurity on;
modsecurity_rules_file /app/openresty/nginx/conf/modsecurity.conf;
#access_log logs/host.access.log main;
if ($access) {
return 403; # 如果$access为1,则拒绝访问
}
location / {
# 应用请求限流
limit_req zone=req_zone burst=20 nodelay;
# 应用连接限制
limit_conn conn_zone 10;
proxy_pass http://127.0.0.1:9080;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 关键部分:重写后端服务器的重定向URL
proxy_redirect default;
# 错误处理
error_page 503 /error503.html;
}
location = /error503.html {
internal;
default_type text/html;
return 503 "Service Unavailable";
}
}
}
配置modsecurity
修改modsecurity.conf添加规则
# 启用 ModSecurity
SecRuleEngine On
# 启用日志记录
SecAuditLog /app/openresty/nginx/logs/modsec_audit.log
SecAuditLogParts ABCJFHZ
SecAuditLogType Serial
# 防止SQL注入和XSS等通用攻击
Include /usr/local/nginx/conf/owasp-modsecurity-crs/crs-setup.conf
Include /usr/local/nginx/conf/owasp-modsecurity-crs/rules/*.conf
# 设置请求体大小限制,防止大请求DDoS攻击
SecRequestBodyLimit 31457280 # 设置请求体最大大小为30MB
SecRequestBodyNoFilesLimit 31457280 # 非文件请求体限制为30MB
# 1. 从X-Forwarded-For头中获取真实客户端IP,并去掉端口号
SecRule REQUEST_HEADERS:X-Forwarded-For "^\d+\.\d+\.\d+\.\d+(:\d+)?$" \
"id:100010,phase:1,pass,t:none,setvar:tx.real_client_ip=%{tx.0},capture,msg:'tx.real_client_ip=%{tx.real_client_ip}'"
# 2. 如果没有X-Forwarded-For头,则使用REMOTE_ADDR作为真实客户端IP,并去掉端口号
SecRule TX:real_client_ip "^$" \
"id:100011,phase:1,pass,t:none,setvar:tx.real_client_ip=%{REMOTE_ADDR},capture"
SecRule TX:real_client_ip "^\d+\.\d+\.\d+\.\d+(:\d+)?$" \
"id:100012,phase:1,pass,t:none,setvar:tx.real_client_ip=%{tx.0}"
# 3. 增加IP计数器,每次访问增加计数
SecRule TX:real_client_ip "^\d+\.\d+\.\d+\.\d+$" \
"id:100002,phase:2,t:none,t:lowercase,log,pass,setvar:ip.dos_counter=+1,expirevar:ip.dos_counter=60,msg:'DOS_COUNTER=%{ip.dos_counter}'"
# 4. 检查请求频率,并标记IP(结合链式规则)
SecRule TX:real_client_ip "^\d+\.\d+\.\d+\.\d+$" \
"id:100001,phase:2,chain,t:lowercase,pass,setvar:tx.dos_detected=1,msg:'Potential DDoS Attack: High Request Rate Detected'"
SecRule IP:DOS_COUNTER "@gt 1"
# 5. 阻止被标记的IP,触发429错误
SecRule TX:dos_detected "@eq 1" \
"id:100003,phase:2,deny,status:429,log,msg:'Potential DDoS Attack: Blocked IP due to excessive requests'"
# 6. 增加连接计数器,每次访问增加计数
SecRule TX:real_client_ip "^\d+\.\d+\.\d+\.\d+$" \
"id:100005,phase:2,t:none,t:lowercase,nolog,pass,setvar:ip.connection_counter=+1,expirevar:ip.connection_counter=60"
# 7. 检查并阻止过多并发连接
SecRule TX:real_client_ip "^\d+\.\d+\.\d+\.\d+$" \
"id:100004,phase:2,chain,t:lowercase,pass,setvar:tx.conn_detected=1,msg:'Potential DDoS Attack: Too many concurrent connections from this IP'"
SecRule IP:CONNECTION_COUNTER "@gt 1"
# 8. 阻止被标记的IP,触发429错误(针对连接)
SecRule TX:conn_detected "@eq 1" \
"id:100009,phase:2,deny,status:429,log,msg:'Potential DDoS Attack: Blocked IP due to excessive connections'"