🚀 第07章 · 访问控制与限流

allow/deny limit_req 安全

访问控制与限流

这一章讲 Nginx 怎么控制"谁可以访问、什么请求能进来、怎么防止被刷"。生产环境光有反向代理还不够,还要能:拦掉不该访问的路径、按 IP 限黑白名单、对敏感接口限流防刷。本机 bangdream.conf 里就有一段"阻止敏感路径被访问"的配置,正是这一章的内容。

1) 路径级访问控制(本机真实示例)

本机在反代 Node 应用前,先挡掉 node_modules、scripts、package.json 等暴露源码/依赖的路径:

# 这些路径一访问就返回 403,避免泄露前端源码
location ~ ^/(node_modules|scripts)/ { return 403; }
location = /package.json { return 403; }
location = /package-lock.json { return 403; }
  • location ~ 用正则匹配。
  • location = 精确匹配(只命中这个确切路径)。
  • return 403 直接返回拒绝。

提示 | 反代前端应用时,务必挡掉 .git、node_modules、package*.json、*.map、.env* 等文件,否则源码和密钥可能被直接下载。

2) IP 黑白名单(allow / deny)

location /admin {
    # 只允许内网和指定 IP
    allow 127.0.0.1;
    allow 192.168.1.0/24;
    allow 203.0.113.10;
    deny all;            # 其余全拒
}

注意 | deny all 放在 allow 之后(顺序很重要,从上到下匹配);allow/deny 只按"来自哪 IP"判,若经过 CDN 会把真实 IP 放在 X-Forwarded-For 里,需配合 real_ip/set_real_ip_from 取真实 IP 再判。

3) 用 X-Real-IP / X-Forwarded-For 取真实 IP(反代场景)

反代之后,$remote_addr 是代理的 IP,客户的真实 IP 在请求头里。Nginx 里常转发:

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

4) 限流(limit_req)

对接口做"每秒允许多少次"的令牌桶限流,防恶意刷接口/密码爆破:

# 定义一个限流桶(rate=10r/s);burst 允许突发 +n;nodelay 突发请求立即放行一小部分
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;

location /api/ {
    limit_req zone=api burst=20 nodelay;
    proxy_pass http://127.0.0.1:3000;
}
指令 作用
limit_req_zone 定义限流区域(按 IP 计 $binary_remote_addr,内存区 10m,速率 10r/s)
limit_req zone=api burst=20 nodelay 应用到 location;burst 是突发余量,nodelay 突发立刻放行(超出的返回 503)
limit_req_status 默认 503,可改成 429

实测 | 超限的请求 Nginx 返回 503 Service Temporarily Unavailable(可设为 429 Too Many Requests 更明确)。用 ab/wrk 压一下即可看到被限流效果。

5) 限制请求体大小(防超大上传)

client_max_body_size 5m;    # 允许上传最大 5M

超过会返回 413 Request Entity Too Large。注意 GitLab 等需大文件上传的场景要调大(本机 gitlab 反代配置里就特意设了 client_max_body_size 0 表示不限制)。

6) 其他常用访问控制

需求 配置
只允许 GET/HEAD if ($request_method !~ ^(GET\|HEAD)$) { return 405; }
禁止某 UA if ($http_user_agent ~* (curl|wget)) { return 403; }
简单暴力防爬 挡 UA + 对访问频率限流
防盗链 if ($http_referer !~ ^https?://(bangdream\.xyz\|lovelive\.top)/) { return 403; }(仅对图片/资源)

警告 | 尽量用 limit_req、allow/deny 等"声明式"指令,少用 if。Nginx 的 if 在某些上下文(如 location 内)有"避坑陷阱"(only safe in server & location, inside location 不一定 + 有坑),能用 map/limit/allow 就不要依赖 if。

相关命令

  • 压测看限流:ab -n 1000 -c 100 http://test/...
  • 看返回码:nick curl -sI 或看 access log 里 429/503。
  • nginx -s reload 让改动生效。