關於Laravel 與 Nginx 限流策略防止惡意請求


一、問題背景

最近公司最近的幾台線上服務器經常出現CPU覆蓋過高,影響部分應用響應超時,產生了大量的短信和郵件報警,經過排查數據庫日志和access.log,發現是API接口被刷,被惡意瘋狂請求,最大一次大概120次/s。

之前沒有過太多這方面經驗,處理起來不是很順暢,這次的問題剛好提了醒,經過這次的問題暴露,來記錄一下解決方案和策略。

線上的部署方案是:nginx + laravel。

首先我們嘗試從nginx層面入手,將占用更少的內存消耗,無需再轉發到php-fpm上處理。
二、(惡意)請求特征

想好很好的特征,就必須捕捉一定的特征,通過這個特征來有效的控制到惡意請求。

短時間內,IP對某接口產生大量請求
user_agent,非正常信息或為空
請求量比平時要高漲很多。

三、限流策略(nginx)

限制請求數

首先的話.就是控制單IP時間上的請求次數和IP連接數,配置如下:

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 / 接口響應耗時。
限制並發連接數

限制完用戶請求頻率后,如果仍然還是存在很大的惡意請求,我們還可以進行並發數的限制。

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請求過於頻繁或者需要完全杜絕該IP的訪問時,可以通過nginx的deny配置來禁止黑名單中的IP訪問。

http {
include blockip.conf;
}

黑名單配置

deny 195.91.112.66;
deny 192.168.2.100;

被添加黑名單后,再次訪問就會出現403禁止訪問.
image
限制UA(user-agent)信息

http {
server {
if ($http_user_agent ~* "curl") {
return 403;
}
}
}

上面就禁止了ua信息為curl的客戶端,直接返回403。

禁止多個ua,通過|來隔斷。

if ($http_user_agent ~* "curl|wget") {
return 403;
}

(四)、限流策略(laravel)

在我們的laravel項目中,存在一個Throttle中間件,該策略,可以在應用層上面,有效抑制用戶可以惡意請求,配置如下:

Route::group(['middleware' => 'throttle:30:1'],function(){
Route::any('/login', 'LoginController@login');
});

在throttle配置中,第一個參數控制了請求數,第二個參數用於控制請求頻率,上面的配置表明,每個客戶端IP每分鍾最大請求30次 login路由。

當客戶端ip超出請求限制后,服務端就會返回429 Too Many Attempts.響應

使用場景
最近,報告查詢系統負載均衡集群相關配置已經完成,兩種實現方式分別是基於Ehcache和Redis的session管理策略。

大家都知道服務器資源有限的,但是客戶端來的請求是無限的(不排除惡意攻擊), 為了保證大部分的請求能夠正常響應,不得不放棄一些客戶端來的請求,所以我們會采用Nginx的限流操作, 這種操作可以很大程度上緩解服務器的壓力, 使其他正常的請求能夠得到正常響應。

如何使用Nginx實現基本的限流,比如單個IP限制每秒訪問50次。通過Nginx限流模塊,我們可以設置一旦並發連接數超過我們的設置,將返回503錯誤給客戶端。這樣可以非常有效的防止CC攻擊。再配合 iptables防火牆,基本上CC攻擊就可以無視了。

如何使用

conf配置

統一在http域中進行配置

限制請求

limit_req_zone $binary_remote_addr $uri zone=api_read:20m rate=50r/s;

按ip配置一個連接 zone

limit_conn_zone $binary_remote_addr zone=perip_conn:10m;

按server配置一個連接 zone

limit_conn_zone $server_name zone=perserver_conn:100m;
server {
listen 80;
server_name report.52itstyle.com;
index login.jsp;
location / {
#請求限流排隊通過 burst默認是0
limit_req zone=api_read burst=5;
#連接數限制,每個IP並發請求為2
limit_conn perip_conn 2;
#服務所限制的連接數(即限制了該server並發連接數量)
limit_conn perserver_conn 1000;
#連接限速
limit_rate 100k;
proxy_pass http://report;
}
}
upstream report {
fair;
server 172.16.1.120:8882 weight=1 max_fails=2 fail_timeout=30s;
server 172.16.1.120:8881 weight=1 max_fails=2 fail_timeout=30s;
}
配置503錯誤
默認情況,超出限制額度,將會報503錯誤,提示:

503 Service Temporarily Unavailable

The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later. Sorry for the inconvenience.
Please report this message and include the following information to us.
Thank you very much!
這樣顯示沒毛病,但是不夠友好,這里我們自定義503錯誤。

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;#自定義50X錯誤
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

配置說明
limit_conn_zone

是針對每個IP定義一個存儲session狀態的容器。這個示例中定義了一個100m的容器,按照32bytes/session,可以處理3200000個session。

limit_rate 300k;

對每個連接限速300k. 注意,這里是對連接限速,而不是對IP限速。如果一個IP允許兩個並發連接,那么這個IP就是限速limit_rate×2。

burst=5;

這相當於在檢查站req旁邊放5個座位。如果某個請求當時超過速度限制被攔了,請他在空座位上坐着,等排隊,如果檢查站空了,就可以通過。如果連座位都坐滿了,那就抱歉了,請求直接退回,客戶端得到一個服務器忙的響應。所以說burst跟request_rate一點關系都沒有,設成10000,就是1萬個請求可以等着排隊,而檢查站還是1秒鍾放行5個請求(龜速)。而且也不能一直排隊,所以nginx還設了超時,排隊超過一定時間,也是直接退回,返回服務器忙的響應。

以上配置Nginx需要配置以下模塊:
ngx_http_limit_conn_module (static)
ngx_http_limit_req_module (static)

執行命令 nginx -V 就可以檢查到是否有安裝。

小結
限流的目的就是防止惡意請求流量,惡意攻擊,或者防止流量超出系統峰值。

實現方案有很多,Nginx的limit模塊只是其中一個思路。對於惡意請求流量,限制訪問到cache層或者對於惡意ip使用nginx deny進行屏蔽。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM