Nginx对客户端的限制

一、引言:为什么需要限制"好"客户端?

在互联网世界,流量既是财富,也可能是灾难。一个设计良好的系统,不仅要能服务海量的正常用户,更要能抵御恶意的、异常的流量冲击。

Nginx 作为 Web 架构的流量入口,天然地承担着"守门人"的角色。通过对客户端施加合理的限制,我们可以:

  • 防止资源耗尽:避免单个恶意 IP 占满所有连接或带宽。
  • 抵御 DDoS/CC 攻击:有效缓解基于 HTTP 的洪水攻击。
  • 保障服务公平性:确保正常用户的请求能得到及时响应。
  • 控制爬虫行为:友好地限制搜索引擎或恶意爬虫的抓取频率。

💡 核心价值

掌握 Nginx 的客户端限制能力,是构建一个健壮、高可用 Web 服务不可或缺的安全基石


二、三大核心限制策略:连接、请求与带宽

Nginx 主要通过三个内置模块来实现对客户端的精细化控制。

1. ngx_http_limit_conn_module - 并发连接数限制

  • 作用 :限制来自同一个客户端(通常是 IP)同时建立的 TCP 连接数量
  • 适用场景:防止单个用户通过大量并发连接耗尽服务器的文件描述符或后端应用的工作线程。
  • 核心指令
    • limit_conn_zone: 定义用于存储连接状态的共享内存区域。
    • limit_conn: 在 http, server, 或 location 块中应用限制规则。

2. ngx_http_limit_req_module - 请求速率限制

  • 作用 :限制来自同一个客户端在单位时间内的请求数量(QPS)。
  • 适用场景:防刷、防爬虫、防 CC 攻击,平滑突发流量。
  • 工作原理 :基于漏桶算法(Leaky Bucket),以恒定速率处理请求。
  • 核心指令
    • limit_req_zone: 定义用于存储请求状态的共享内存区域,并设置速率。
    • limit_req: 应用限制规则,并可配置突发 (burst) 和是否延迟 (nodelay)。

3. limit_rate - 单连接带宽限制

  • 作用 :限制单个连接向客户端传输数据的最大速率。
  • 适用场景:防止大文件下载占满出口带宽,影响其他用户;实现简单的 QoS (服务质量) 策略。
  • 核心指令
    • limit_rate: 设置速率(字节/秒)。

三、实战配置详解

1. 限制并发连接数

复制代码
http {
    # 定义一个名为 "perip" 的共享内存区域,大小为 10MB,
    # 用于存储客户端 IP ($binary_remote_addr) 的连接计数。
    limit_conn_zone $binary_remote_addr zone=perip:10m;

    server {
        listen 80;
        server_name example.com;

        location / {
            # 限制每个 IP 最多只能有 20 个并发连接
            limit_conn perip 20;
            
            # 可选:自定义超过限制时返回的状态码
            limit_conn_status 503; 
            
            proxy_pass http://backend;
        }
    }
}
  • $binary_remote_addr: 使用二进制格式存储 IP 地址,比字符串格式更节省内存。
  • zone=perip:10m: 共享内存区域名必须唯一,10MB 内存大约可以存储 16 万个 IP 地址的状态。

2. 限制请求速率(带突发)

复制代码
http {
    # 定义一个名为 "one" 的共享内存区域,大小为 10MB,
    # 限制每个 IP 的请求速率为每秒 10 个 (10r/s)。
    limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;

    server {
        location /api/ {
            # 应用限制规则
            # burst=20: 允许突发最多 20 个额外请求进入"缓冲队列"
            # nodelay: 不延迟处理突发的请求,直接放行(否则会按速率匀速处理)
            limit_req zone=one burst=20 nodelay;
            
            proxy_pass http://api_backend;
        }
    }
}
  • burst : 漏桶的容量。当请求速率超过 rate 时,多余的请求(不超过 burst)会被暂时放入队列。
  • nodelay : 如果不加此参数,突发的请求会被延迟处理,以保证平均速率不超过 rate。加上后,突发请求会立即被处理,但一旦 burst 队列满,后续请求将被拒绝。

3. 限制单连接带宽

复制代码
server {
    location /download/ {
        # 限制每个连接的下载速度为 128KB/s
        limit_rate 128k;
        
        # 可以结合内部变量实现动态限速
        # 例如,对特定 User-Agent 限速
        if ($http_user_agent ~* "BadBot") {
            set $limit_rate 1k;
        }
        
        alias /path/to/files/;
    }
}
  • limit_rate 128k : kK 表示千字节/秒,mM 表示兆字节/秒。

四、高级技巧与注意事项

1. 识别真实客户端 IP

如果 Nginx 前面还有 CDN 或代理(如 LVS, HAProxy),$remote_addr 获取到的是代理服务器的 IP,而非真实用户 IP。此时需要配合 real_ip 模块:

复制代码
set_real_ip_from 192.168.1.0/24; # 可信代理的IP段
real_ip_header X-Forwarded-For;   # 从该Header中获取真实IP
real_ip_recursive on;             # 递归解析X-Forwarded-For

# 之后再使用 $realip_remote_addr 或重新赋值 $binary_remote_addr
map $realip_remote_addr $client_ip {
    "" $remote_addr;
    default $realip_remote_addr;
}
limit_conn_zone $client_ip zone=real_perip:10m;

2. 白名单机制

对于重要的合作伙伴或监控系统,我们通常需要将其加入白名单,豁免限制。可以结合 geo 模块实现:

复制代码
geo $limited_ip {
    default 1;          # 默认所有IP都需要被限制
    10.0.0.0/8 0;       # 内网IP豁免
    1.2.3.4 0;          # 特定IP豁免
}

map $limited_ip $limit_key {
    0 "";               # 豁免IP,映射为空字符串
    1 $binary_remote_addr; # 需要限制的IP,映射为其IP
}

limit_req_zone $limit_key zone=api:10m rate=10r/s;

location /api/ {
    limit_req zone=api burst=20 nodelay;
}

3. 日志记录与监控

access_log 中记录被限制的请求,便于后续分析和告警。

复制代码
log_format main_ext '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent" '
                    'rt=$request_time uct="$upstream_connect_time" '
                    'uht="$upstream_header_time" urt="$upstream_response_time" '
                    'limit_req_status=$limit_req_status'; # 记录限流状态

access_log /var/log/nginx/access.log main_ext;

五、结语

感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!

相关推荐
华奥系科技2 小时前
汛期城市内涝治理:智慧水务如何重塑防汛“安全感”?
大数据·运维·人工智能
IT WorryFree2 小时前
三套 Zabbix7.4 API 可直接复制 params 模板
运维·服务器·网络
Full Stack Developme2 小时前
Linux rm-rf 执行后,硬盘空间变化
linux·运维·服务器
跨境数据猎手3 小时前
独立站搭建:架构拆解+源码配置+运维复盘
运维·架构
楠目3 小时前
CVE-2017-7529 Nginx Range头整数溢出漏洞利用总结
运维·nginx
江湖有缘3 小时前
Docker部署HamsterBase Tasks任务管理工具
运维·docker·容器
huangdong_4 小时前
1688商品图片批量下载与SKU图自动分类技术完整实现方案
运维·服务器
yyuuuzz4 小时前
独立站运营的几个技术层面常见问题
大数据·运维·服务器·网络·数据库·aws
MXsoft6184 小时前
**用自动化脚本给MAC误阻断留条后路:可审计、可回滚的准入控制方案**
运维·macos·自动化