每天進步一點點...
新建的網站,如何限制別人惡意攻擊、頻繁請求介面,導致資料庫崩潰?我們可以使用Redis對請求的IP做一個簡單的限制。
一、設計思路1、Redis中使用有序set表存放黑名單列表、頻繁請求列表。
2、使用者訪問,設定一個鎖,數值為1,過期時間10秒。
3、使用者每次請求介面1次,鎖的數值加1。在10秒內介面訪問次數超過20次,則把該使用者IP或uid新增到頻繁請求列表中,score的值為當前時間,資料庫表頻繁請求次加1。
4、若頻繁請求次數超過設定次數,則新增到redis黑名單列表中。
二、前期準備1、在app\http\common中建立RedisKey.php
<?phpnamespace App\Http\Common;class RedisKey{ public static $USER_BLACK_LIST = "user:black:list";//黑名單列表 public static $USER_FREQUENT_REQUEST_LIST = "user:frequent:request:list";//頻繁請求列表 public static $USER_FREQUENT_REQUEST_LOCK = "user:frequent:request:lock";//鎖}
2、建立資料庫表
user表
3、使用命令建立CheckRequest.php路由中介軟體
php artisan make:middleware CheckRequest
三、實現程式碼
<?phpnamespace App\Http\Middleware;use App\Http\Common\Code;use App\Http\Common\RedisKey;use App\Models\FrontUser;use Closure;use Illuminate\Http\Request;use Illuminate\Support\Facades\Redis;class CheckRequest{ /** * Handle an incoming request. * * @param Request $request * @param Closure $next * @return mixed */ public function handle($request, Closure $next) { $ip = request()->ip(); //檢視redis黑名單中是否存在該IP $isBlack = Redis::zscore(RedisKey::$USER_BLACK_LIST, $ip); if ($isBlack) { return ["code" => Code::$USER_BLACK, "msg" => "由於您近期異常請求過於頻繁,已限制訪問。如需取消限制,請聯絡管理員:郵箱[email protected]!"]; } $user = new FrontUser(); $isUser = $user->where(["ip" => $ip])->first(); //資料庫中已設定為黑名單或頻繁請求數大於等於10 if ($isUser) { //檢視資料庫表中頻繁請求次數是否超過10次,是就把該使用者列入黑名單並修改相關欄位 if ($isUser->black_list === 1 || $isUser->frequent_num >= 10) { $isUser->black_list = 1; $isUser->save(); Redis::zadd(RedisKey::$USER_BLACK_LIST, 1, $isUser->ip); return ["code" => Code::$USER_BLACK, "msg" => "由於您近期異常請求過於頻繁,已限制訪問。如需取消限制,請聯絡管理員:郵箱[email protected]!"]; } } $time = 5;//鎖過期時間 $limit = 20;//5秒內請求次數,超過就觸發防刷機制 $lock_time = 60;//每次防刷的鎖60秒 //redis頻繁請求列表 $start_time = Redis::zscore(RedisKey::$USER_FREQUENT_REQUEST_LIST, $ip); //如果redis頻繁請求列表中存在該使用者IP,且間隔當前時間少於60秒 if (time() - $start_time < $lock_time) { //返回剩餘時間 return response(["code" => Code::$USER_FREQUENT, "msg" => "頻繁請求!", "data" => $lock_time - (time() - $start_time)]); } $frequentLock = RedisKey::$USER_FREQUENT_REQUEST_LOCK . ":" . $ip; $isFrequent = Redis::get($frequentLock); if (!$isFrequent) { Redis::setex($frequentLock, $time, 1); //設定鎖 return $next($request); } Redis::incr($frequentLock);//鎖過期時間類數值自增 //設定時間內請求次數大於設定次數,觸發防刷機制 if ($isFrequent > $limit) { Redis::zadd(RedisKey::$USER_FREQUENT_REQUEST_LIST, time(), $ip); Redis::expire(RedisKey::$USER_FREQUENT_REQUEST_LIST, 60 * 5); $isUser->increment("frequent_num"); $isUser->save(); } return $next($request); }}
四、實現效果效果圖
最新評論