🚀 第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让改动生效。