完整示例使用了日志格式化 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.conf
user 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 编辑过