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