Laravel API 资源如何限制频率防止恶意刷接口请求

文章导读
在 Laravel 中防止接口被恶意刷请求,最稳妥的做法是使用框架内置的速率限制中间件,并配合 Redis 缓存驱动实现分布式计数。
📋 目录
  1. A 实施步骤
  2. B 验证方法
  3. C 常见坑
  4. D 参考来源
A A

在 Laravel 中防止接口被恶意刷请求,最稳妥的做法是使用框架内置的速率限制中间件,并配合 Redis 缓存驱动实现分布式计数。

先说结论:直接启用 Laravel 自带的 throttle 中间件,并将缓存驱动配置为 Redis 以确保多实例环境下计数准确。

  • 先判断:确认你的应用是否部署在多台服务器或使用了负载均衡,这决定了是否需要共享缓存。
  • 优先做:在路由组或特定接口上绑定 throttle 中间件,并定义合理的限制规则。
  • 再验证:通过脚本连续发送请求,观察是否返回 429 状态码。

实施步骤

核心是在路由定义中添加中间件,并确保缓存驱动支持共享。以下是具体配置流程。

第一步:配置缓存驱动

检查 .env 文件,确保缓存存储设置为 redis。Laravel 9+ 及 11 版本推荐使用 CACHE_STORE 变量,旧版本可能使用 CACHE_DRIVER

CACHE_STORE=redis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

修改后需执行 php artisan config:clear 使配置生效。

第二步:定义速率限制规则

需要在应用启动时注册限制器。在 Laravel 8-10 中,通常在 RouteServiceProvider 的 boot 方法里;在 Laravel 11 中,由于移除了 RouteServiceProvider,建议在 AppServiceProvider 的 boot 方法或 bootstrap/app.php 中通过 withMiddleware 配置。

Laravel API 资源如何限制频率防止恶意刷接口请求
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Http\Request;

RateLimiter::for('api', function (Request $request) {
    return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
});

这段代码优先按用户 ID 限制,未登录用户则按 IP 限制。

第三步:应用中间件

在路由上使用刚才定义的 limiter 名称。Laravel 默认提供了 throttle:api,也可以自定义名称。

Route::middleware(['throttle:api'])->group(function () {
    // 你的受保护接口
    Route::get('/user', [UserController::class, 'show']);
});

验证方法

不要只用浏览器刷新,因为浏览器可能会缓存或有其他干扰。使用 curl 或 Postman 进行压力测试。

检查命令:

# 循环发送 70 次请求,观察后 10 次是否被拒绝
for i in {1..70}; do curl -w "%{http_code}\n" -o /dev/null -s http://your-domain.com/api/test; done

状态判断:

前 60 次请求应该返回 200 状态码,之后的请求应该返回 429 状态码。同时检查响应头中是否包含 X-RateLimit-LimitX-RateLimit-Remaining 字段,这些字段能告诉客户端剩余配额。

Laravel API 资源如何限制频率防止恶意刷接口请求

常见坑

1. 负载均衡后的 IP 识别问题

如果应用部署在 Nginx 或其他负载均衡器后面,$request->ip() 获取的可能是内网 IP,导致所有用户被当成同一个 IP 限制。需要配置信任代理。

在 Laravel 8-10 中,确保 App\Http\Middleware\TrustProxies 中间件已启用并配置 $proxies 属性。在 Laravel 11 中,通常在 bootstrap/app.php 中通过 withMiddleware 方法配置信任代理,例如:$middleware->trustProxies(at: '*'),以便框架能读取 X-Forwarded-For 头获取真实用户 IP。

2. 缓存驱动不一致

开发环境常用 file 或 array 驱动,生产环境用 Redis。如果代码中硬编码了依赖特定缓存行为的逻辑,部署后可能失效。务必在 .env 中区分环境配置,并确保生产环境 CACHE_STORE 不为 array。

3. 静态资源被误伤

不要对全站开启严格的频率限制,尤其是 CSS、JS 和图片请求。建议只对 API 路由组或特定的 Web 接口组应用 throttle 中间件,避免影响正常页面加载。

参考来源

  • Laravel Official Documentation - Rate Limiting, URL: https://laravel.com/docs/routing#rate-limiting
  • Laravel Official Documentation - Cache Configuration, URL: https://laravel.com/docs/cache