最近公司最近的幾臺線上服務器常常出現CPU覆蓋太高,影響部分應用響應超時,產生了大量的短信和郵件報警,通過排查數據庫日誌和access.log,發現是API接口被刷,被惡意瘋狂請求,最大一次大概120次/s。php
以前沒有過太多這方面經驗,處理起來不是很順暢,此次的問題恰好提了醒,通過此次的問題暴露,來記錄一下解決方案和策略。nginx
線上的部署方案是:nginx + laravel。laravel
首先咱們嘗試從nginx層面入手,將佔用更少的內存消耗,無需再轉發到php-fpm上處理。算法
想好很好的特徵,就必須捕捉必定的特徵,經過這個特徵來有效的控制到惡意請求。數據庫
首先的話.就是控制單IP時間上的請求次數和IP鏈接數,配置以下:api
http { limit_req_zone $binary_remote_addr zone=one:1m rate=1r/s; server { location /api/ { limit_req zone=one burst=5; } } }
limit_req_zone主要控制單個IP的請求速率,使用漏桶算法來完成限制,limit_req_zone size,主要用於儲存統計IP的請求信息,1M能夠儲存16000個IP,當每秒的請求超過了16000個的時候,其他訪問都會被訪問503 服務暫不可用。服務器
上面的模板設置了,每秒最大不超過1個請求,最大延遲請求不超過5個。併發
若是咱們的服務器每次接口的響應時間是在200ms-300ms,那咱們對應的每秒的限制就應該設置成 1000ms / 接口響應耗時
。curl
限制完用戶請求頻率後,若是仍然仍是存在很大的惡意請求,咱們還能夠進行併發數的限制。php-fpm
http { limit_conn_zone $binary_remote_addr zone=one:1m; server { location /api/ { limit_conn one 10; } } }
limit_conn_zone:主要是用於控制請求併發數,頻率不能太快。
limit_conn_zone size跟limit_req_zone意思一致,可根據須要動態調控,上面的案例中,表示限制每一個客戶端IP最大併發鏈接數爲10。
當某個IP請求過於頻繁或者須要徹底杜絕該IP的訪問時,能夠經過nginx的deny配置來禁止黑名單中的IP訪問。
http { include blockip.conf; }
黑名單配置
deny 195.91.112.66; deny 192.168.2.100;
被添加黑名單後,再次訪問就會出現403禁止訪問.
http { server { if ($http_user_agent ~* "curl") { return 403; } } }
上面就禁止了ua信息爲curl的客戶端,直接返回403。
禁止多個ua,經過|來隔斷。
if ($http_user_agent ~* "curl|wget") { return 403; }
在咱們的laravel項目中,存在一個Throttle中間件,該策略,能夠在應用層上面,有效抑制用戶能夠惡意請求,配置以下:
Route::group(['middleware' => 'throttle:30:1'],function(){ Route::any('/login', 'LoginController@login'); });
在throttle配置中,第一個參數控制了請求數,第二個參數用於控制請求頻率,上面的配置代表,每一個客戶端IP每分鐘最大請求30次 login
路由。
當客戶端ip超出請求限制後,服務端就會返回429 Too Many Attempts.
響應