完整示例使用了日志格式化 json,方便查看业务日志与各种日志收集。
Nginx Geo模块设置与map模块设置的优缺点目录:
一、geo模块完整示例
二、ip地址太多了改成文件引入形式
三、map模块完整示例
两种方案的比较
特性 | 方案一(文件引入) | 方案二(直接map) |
性能 | 更高(使用geo模块) | 较低 |
IP数量支持 | 支持大量IP | 适合少量IP |
维护性 | 更好(分离文件) | 一般 |
CIDR支持 | 完整支持 | 需要正则表达式 |
多层代理处理 | 更完善 | 一般 |
黑白名单逻辑分离 | 是 | 合并处理 |
推荐使用方案一(文件引入形式),因为:
1.性能更好,适合大量IP规则
2.维护更方便,IP列表可以单独管理
3.支持CIDR格式,更规范
4.黑白名单逻辑分离,更清晰
5.多层代理处理更完善
一、geo模块完整示例
1. 主配置文件 /usr/local/nginx/conf/nginx.conf
user www www;worker_processes 4;error_log /data/logs/nginx/error.log;events { worker_connections 10240;}http { include mime.types; default_type application/octet-stream; charset utf-8; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; log_format web_log_json escape=json '{"@timestamp":"$time_iso8601", ' '"remoteIP":"$remote_addr", ' '"clientIP":"$http_x_forwarded_for", ' '"logTime":"$time_local", ' '"uri":"$uri", ' '"requestURI":"$request_uri", ' '"requestMethod":"$request_method", ' '"httpMethod":"$scheme", ' '"status":$status, ' '"servername":"$host", ' '"upstream_name":"$proxy_host", ' '"upstream_addr":"$upstream_addr", ' '"upstream_status":$upstream_status, ' '"upstream_response_time":$upstream_response_time, ' '"responseBytes":$body_bytes_sent, ' '"requestBytes":$request_length, ' '"responseTime":$request_time, ' '"referer":"$http_referer", ' '"userAgent":"$http_user_agent"}'; log_format web_log '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '$host $proxy_host $upstream_addr $upstream_status $upstream_response_time $args' '"$http_user_agent" "$http_x_forwarded_for"'; sendfile on; keepalive_timeout 180; client_header_buffer_size 128k; client_max_body_size 2560M; large_client_header_buffers 4 128k; proxy_read_timeout 180; proxy_connect_timeout 180; server_names_hash_max_size 2048; server_names_hash_bucket_size 128; proxy_max_temp_file_size 2048m; # WebSocket支持 map $http_upgrade $connection_upgrade { default upgrade; '' close; } # 真实客户端IP提取(处理多层代理如阿里云CLB) map $http_x_forwarded_for $real_client_ip { # 提取第一个IP(最左边的IP是客户端真实IP) ~^([^,]+) $1; # 如果没有XFF头,使用remote_addr default $remote_addr; } # 白名单配置 - 使用geo模块(高性能IP匹配) geo $whitelist { default 0;
# 您原有的IP段(转换为CIDR格式) 113.201.50.0/24 1; 123.139.52.0/24 1; 222.91.198.0/24 1; 117.22.144.0/24 1; 125.76.162.0/24 1; 125.76.161.0/24 1; 125.76.177.0/24 1; 125.76.163.0/24 1;
# 可以添加更多IP或网段 # 10.10.50.0/24 1; } # 黑名单配置 - 使用geo模块 geo $blacklist { default 0;
# 您原有的黑名单IP 218.90.199.0/24 1; 58.222.32.0/24 1; 58.222.26.0/24 1; 58.222.25.0/24 1; } # 访问控制逻辑 map $real_client_ip $access_control { # 如果在黑名单中,拒绝 ~ $blacklist 1 { return 403; }
# 如果不在白名单中,拒绝 ~ $whitelist 0 { return 403; }
# 默认允许 default 1; } # 包含虚拟主机配置 include /usr/local/nginx/conf/vhost/*.conf;}
虚拟主机配置示例(vhost/example.conf)
server { listen 80; server_name example.com;
access_log /data/logs/nginx/example.access.log web_log_json; error_log /data/logs/nginx/example.error.log;
location /static/ { alias /data/www/example/static/; expires 30d; access_log off; }
location / {
proxy_pass http://backend_servers; proxy_set_header Host $host; proxy_set_header X-Real-IP $real_client_ip; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 60s; proxy_read_timeout 60s; proxy_send_timeout 60s;
proxy_buffer_size 128k; proxy_buffers 4 256k; proxy_busy_buffers_size 256k; }
location /health { access_log off; return 200 "OK"; }}upstream backend_servers { server 10.0.0.1:8080 weight=5; server 10.0.0.2:8080 weight=5; keepalive 32;}
二、ip地址太多了改成文件引入形式
1. 主配置文件 /usr/local/nginx/conf/nginx.conf
user www www;worker_processes 4;error_log /data/logs/nginx/error.log;events { worker_connections 10240;}http { include mime.types; default_type application/octet-stream; charset utf-8; # 日志格式(保持原有) log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"';
log_format web_log_json escape=json '{"@timestamp":"$time_iso8601", ' '"remoteIP":"$remote_addr", ' '"clientIP":"$http_x_forwarded_for", ' '"logTime":"$time_local", ' '"uri":"$uri", ' '"requestURI":"$request_uri", ' '"requestMethod":"$request_method", ' '"httpMethod":"$scheme", ' '"status":$status, ' '"servername":"$host", ' '"upstream_name":"$proxy_host", ' '"upstream_addr":"$upstream_addr", ' '"upstream_status":$upstream_status, ' '"upstream_response_time":$upstream_response_time, ' '"responseBytes":$body_bytes_sent, ' '"requestBytes":$request_length, ' '"responseTime":$request_time, ' '"referer":"$http_referer", ' '"userAgent":"$http_user_agent"}'; sendfile on; keepalive_timeout 180; client_header_buffer_size 128k; client_max_body_size 2560M; large_client_header_buffers 4 128k; proxy_read_timeout 180; proxy_connect_timeout 180; server_names_hash_max_size 2048; server_names_hash_bucket_size 128; proxy_max_temp_file_size 2048m; # WebSocket支持 map $http_upgrade $connection_upgrade { default upgrade; '' close; } # 真实客户端IP提取 map $http_x_forwarded_for $real_client_ip { ~^([^,]+) $1; default $remote_addr; } # 白名单配置 - 从外部文件加载 geo $whitelist { default 0; include /usr/local/nginx/conf/whitelist_ips.conf; } # 黑名单配置 - 从外部文件加载 geo $blacklist { default 0; include /usr/local/nginx/conf/blacklist_ips.conf; } # 访问控制逻辑 map $real_client_ip $access_control { ~ $blacklist 1 { return 403; } ~ $whitelist 0 { return 403; } default 1; } include /usr/local/nginx/conf/vhost/*.conf;}
2. 白名单IP文件 /usr/local/nginx/conf/whitelist_ips.conf
113.201.50.0/24 1;123.139.52.0/24 1;222.91.198.0/24 1;117.22.144.0/24 1;125.76.162.0/24 1;125.76.161.0/24 1;125.76.177.0/24 1;125.76.163.0/24 1;
3. 黑名单IP文件 /usr/local/nginx/conf/blacklist_ips.conf
218.90.199.0/24 1;58.222.32.0/24 1;58.222.26.0/24 1;58.222.25.0/24 1;
三、map模块完整示例
1. 主配置文件 /usr/local/nginx/conf/nginx.conf
$ cat /usr/local/nginx/conf/nginx.confuser www www;worker_processes 4;error_log /data/logs/nginx/error.log;#error_log logs/error.log notice;#error_log logs/error.log info;#pid logs/nginx.pid;events { worker_connections 10240;}http { include mime.types; default_type application/octet-stream; charset utf-8; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; log_format web_log_json escape=json '{"@timestamp":"$time_iso8601", ' '"remoteIP":"$remote_addr", ' '"clientIP":"$http_x_forwarded_for", ' '"logTime":"$time_local", ' '"uri":"$uri", ' '"requestURI":"$request_uri", ' '"requestMethod":"$request_method", ' '"httpMethod":"$scheme", ' '"status":$status, ' '"servername":"$host", ' '"upstream_name":"$proxy_host", ' '"upstream_addr":"$upstream_addr", ' '"upstream_status":$upstream_status, ' '"upstream_response_time":$upstream_response_time, ' '"responseBytes":$body_bytes_sent, ' '"requestBytes":$request_length, ' '"responseTime":$request_time, ' '"referer":"$http_referer", ' '"userAgent":"$http_user_agent"}'; log_format web_log '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '$host $proxy_host $upstream_addr $upstream_status $upstream_response_time $args' '"$http_user_agent" "$http_x_forwarded_for"'; sendfile on; #server_tokens off; keepalive_timeout 180; client_header_buffer_size 128k; client_max_body_size 2560M; large_client_header_buffers 4 128k; proxy_read_timeout 180; proxy_connect_timeout 180; server_names_hash_max_size 2048; server_names_hash_bucket_size 128; proxy_max_temp_file_size 2048m; map $http_upgrade $connection_upgrade { default upgrade; '' close; }
# 真实客户端IP提取 map $http_x_forwarded_for $real_client_ip { ~^([^,]+) $1; default $remote_addr; } # 访问控制逻辑 map $real_client_ip $access_control { ~ $blacklist 1 { return 403; } ~ $whitelist 0 { return 403; } default 1; }
#访问白名单控制 map $http_x_forwarded_for $accessip { default false; #10.10.50.0/24(网段匹配) ~*113.201.50. true; ~*123.139.52. true; ~*222.91.198. true; ~*117.22.144. true; ~*125.76.162. true; ~*125.76.161. true; ~*125.76.177. true; ~*125.76.163. true; } #访问黑名单控制 map $http_x_forwarded_for $denyip { default true; #10.10.50.0/24(网段匹配) ~*218.90.199. false; ~*58.222.32. false; ~*58.222.26. false; ~*58.222.25. false; } include /usr/local/nginx/conf/vhost/*.conf; }
server { listen 80; server_name example.com;
access_log /data/logs/nginx/example.access.log web_log_json; error_log /data/logs/nginx/example.error.log;
if ($allow_access = 0) { return 403 "Forbidden"; }
location / { proxy_pass http://backend_servers; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }
location /static/ { alias /data/www/static/; expires 30d; }}upstream backend_servers { server 10.0.0.1:8080; server 10.0.0.2:8080;}
白名单与黑名单的协同作用:深入解析访问控制策略
双名单机制的核心价值
当您看到同时存在白名单和黑名单配置时,这代表了分层安全策略,它们协同工作实现更精细的访问控制:
map $http_x_forwarded_for $accessip { default false; ~*113.201.50. true; ...}
map $http_x_forwarded_for $denyip { default true; ~*218.90.199. false; ...}
分层安全机制的意义
双名单协同工作的典型场景
场景1:白名单基础上的风险IP排除
location / { if ($accessip = false) { return 403; }
if ($denyip = true) { return 403; }
}
1. 请求进入2. 检查是否在白名单中? → 否:立即拒绝 → 是:继续下一步3. 检查是否在黑名单中? → 是:拒绝访问(优先级高于白名单) → 否:允许访问
场景2:特殊权限分配(白名单中的例外)
location /admin { if ($accessip = false) { return 403; }
if ($denyip = true) { return 403 "Admin access restricted"; }
}
为什么不只用白名单?
单一白名单的局限性及双名单解决方案:
| | |
|---|
| 白名单IP被入侵 | | |
| IP地址重用风险 | | |
| 临时权限需求 | | |
| 异常行为检测 | | |
先进用法:动态安全策略
结合实时威胁情报
map $http_x_forwarded_for $threat_intel { default 0; include /etc/nginx/threat-feeds/*.conf;}
location / { if ($accessip = false) { return 403; }
if ($threat_intel) { log security_alert "Blocked known threat actor: $http_x_forwarded_for"; return 444; }
if ($denyip = true) { return 403; }}
基于行为的智能拦截
limit_req_zone $http_x_forwarded_for zone=perip:10m rate=10r/s;
location /login { if ($accessip = false) { return 403; }
limit_req zone=perip burst=20 nodelay;
if ($denyip = true) { return 403; }
}
何时应该使用双名单?
双名单策略特别适用于:
总结
白名单(allowlist)和黑名单(denylist)不是相互替代,而是深度防御体系中的互补层级:
这种双重机制在复杂网络环境中提供了更灵活的访问控制能力,特别是在企业安全、云原生应用和合规要求严格的场景中具有独特价值。有效的安全策略应像洋葱一样多层防护,而不是单一的硬壳。
阅读原文:原文链接
该文章在 2025/7/21 10:16:56 编辑过