Nginx前置漏桶限流是拦截恶意刷量的首要防线:先在http块定义limit_req_zone $binary_remote_addr zone=ip_api:10m rate=5r/s,再于location ^~ /api/中配置limit_req zone=ip_api burst=10 nodelay,并可叠加X-Device-ID二级限流,确保超限请求立即返回503,不进PHP层。

线上Laravel应用遭遇每秒上百次恶意接口刷量,CPU飙升、响应超时、短信报警频发,单靠PHP层限流已无法拦截流量洪峰,必须让Nginx在请求进入PHP前就完成识别与拦截。
Nginx层做漏桶式前置限流
这一步必须放在最前面——所有请求先过Nginx,不进PHP就不消耗FPM进程和数据库连接。
第一步:在http块顶部定义IP级请求速率区,用$binary_remote_addr而非$remote_addr节省内存:limit_req_zone $binary_remote_addr zone=ip_api:10m rate=5r/s;
第二步:为/api/路径启用该区域,并允许短时突发10个请求立即通过:location ^~ /api/ { limit_req zone=ip_api burst=10 nodelay; }
第三步:若业务支持传X-Device-ID,再加一层设备级限流,比IP更精准防共享网络误杀:limit_req_zone $http_x_device_id zone=device_api:10m rate=30r/m; → 在同一location块中追加:limit_req zone=device_api burst=5;
【burst=10 nodelay必须同时出现】否则超限请求会排队等待,反而加剧后端堆积;加了nodelay才真正实现“超了立刻503”,不给攻击者试探窗口。
Laravel中间件做语义级行为过滤
当请求已通过Nginx放行,说明它“看起来合法”,这时中间件要判断它“是否真合理”——比如带有效Token却1秒调用15次短信接口。
方法一:重写throttle中间件的key生成逻辑,在AppServiceProvider::boot()中注册:
RateLimiter::for('api', function (Request $request) {<br> return Limit::perMinute(30)->by($request->user()? $request->user()->id : $request->ip());<br>});
方法二:自定义中间件检查User-Agent和Referer,直接拦截空UA、curl、python-requests等自动化标识:if (in_array(strtolower($request->header('User-Agent')), ['curl', 'python-requests', '']) || !$request->header('Referer')) { abort(403); }
方法三:对高危接口(如/api/v1/sms)强制校验时间戳+签名,且签名有效期严格控制在60秒内,过期即拒。
用Nginx连接数限制防慢速攻击
攻击者不用发大量请求,只要维持数百个长连接不关闭,就能耗尽服务器的max_connections,导致正常用户无法建连。
在http块中添加连接数限制区:limit_conn_zone $binary_remote_addr zone=conn_ip:10m;
在/api/ location中启用:limit_conn conn_ip 8;
必须同步设置超时参数,否则慢速攻击仍可得手:
client_header_timeout 15;<br>client_body_timeout 15;<br>keepalive_timeout 30;
注意:如果使用CDN或反向代理,$binary_remote_addr会变成代理IP,必须配置real_ip_header X-Forwarded-For;并指定set_real_ip_from可信网段,否则限流失效。
敏感接口分级限流与黑名单联动
登录、短信、支付等接口风险等级不同,不能全站统一限速。Nginx支持按路径精细控制。
① 为登录接口单独设严控策略:
location = /login {<br> limit_req zone=ip_api burst=2 nodelay;<br> limit_conn conn_ip 3;<br> proxy_pass http://php_backend;<br>}
② 短信接口加人工验证兜底:
error_page 429 = @captcha;<br>location @captcha {<br> return 200 '<html><body><h1>请完成验证</h1><script src="https://challenges.cloudflare.com/turnstile/v0/api.js"></script><div class="cf-turnstile" data-sitekey="YOUR_KEY"></div></body></html>';<br>}
③ 静态资源路径(.js、.css、.png)不限速但关闭日志,减少磁盘IO压力:
location ~* \.(js|css|png|jpg|gif)$ {<br> limit_req zone=ip_api burst=50;<br> access_log off;<br>}
④ 黑名单IP直接跳过计数逻辑,使其瞬间触发限流阈值被拒:
geo $bad_ip { default 0; 192.168.10.5 1; }<br>map $bad_ip $limit_key { 1 ""; 0 $binary_remote_addr; }<br>limit_req_zone $limit_key zone=guarded:10m rate=1r/s;



















