Nginx1.16訪問限制


如何設置能限制某個IP某一時間段的訪問次數,特別面對惡意的DDOS攻擊的時候。其中CC攻擊(Challenge Collapsar)是DDOS(分布式拒絕服務)的一種,也是一種常見的網站攻擊方法,攻擊者通過代理服務器或者肉雞向受害主機不停地發大量數據包,造成對方服務器資源耗盡,一直到宕機崩潰。

Nginx可以通過限制IP訪問次數、添加IP黑名單、禁止代理訪問等配置防御DDOS,CC等流量攻擊。

CC攻擊一般就是使用有限的IP數對服務器頻繁發送數據來達到攻擊的目的,Nginx可以通過 ngx_http_limit_conn_module 和 ngx_http_limit_req_module 配置來限制IP在同一時間段的訪問次數來防CC攻擊。

ngx_http_limit_req_module:該模塊用來限制單個的IP地址的請求的處理速率,使用“泄漏桶”方法進行限制,指令 limit_req_zone 和 limit_req 配合使用來達到限制。一旦並發連接超過指定數量,就會返回503錯誤。

ngx_http_limit_conn_module:該模塊用來限制單個IP​​地址的並發連接數,使用 limit_conn_zone 和 limit_conn 指令。

這兩個模塊的區別是前者對一段時間內的連接數限制,后者是對同一時刻的連接數限制。

注意:Nginx是用yum安裝的,配置文件目錄和其他方式安裝的不同

一、使用ngx_http_limit_req_module模塊

ngx_http_limit_req_module 模塊使用官方文檔:http://nginx.org/en/docs/http/ngx_http_limit_req_module.html

ngx_http_limit_req_module模塊用於限制單一IP地址的請求的處理速率,使用“漏斗”方法完成限制

打開配置文件

vim /etc/nginx/nginx.conf

在http段下寫入以下配置

limit_req_zone $binary_remote_addr zone=req_zone:10m rate=1r/s;

單個配置說明:

limit_req_zone:限制請求

$binary_remote_addr:二進制IP地址

zone=req_zone:限制策略的名稱

10m:占用10M內存空間

rate=1r/s:允許每秒1次請求

整個配置說明:

設置共享內存區域名稱和大小以及請求速率。

定義一個名為req_zone的limit_req_zone用來存儲session,大小是10M內存,以變量 $binary_remote_addr 作為會話的判斷基准(即一個地址一個會話),限制每秒的請求為1個(包括各種請求,例如ajax,例如img的src,如果給的過少會導致上述請求返回503錯誤,另外這里的單位也可以改成每分鍾,例如每兩秒一個請求,30r/m)。

$binary_remote_addr變量的大小對於IPv4地址總是4字節,對於IPv6地址總是16字節。存儲狀態在32位平台上總是占用64字節,在64位平台上占用128字節。一個兆字節區域可以保持大約1.6萬個64字節的狀態或大約8千個128字節的狀態。

如果區域存儲已用盡,則將刪除最近最少使用的狀態。即使在此之后無法創建新狀態,請求也會因503錯誤終止。

在server段或者location段引用限制策略的名稱

打開配置文件,注意:不是之前的/etc/nginx/nginx.conf配置文件

vim /etc/nginx/conf.d/default.conf

在server段或者location段寫入以下配置:

limit_req zone=req_zone;
#limit_req zone=req_zone burst=5;
#limit_req zone=req_zone burst=5 nodelay;

配置說明:

limit_req zone=req_zone:引用限制策略名稱,和http段定義的zone=req_zone名稱要一致

下面對注釋掉的12行和13行中的 burst=5 和 nodelay 配置做個說明

burst=5:平均每秒最多允許不超過1個請求,並且突發不超過5個請求。

nodelay:平均每秒允許不超過1個請求,突發請求不超過5個,如果不希望在請求有限的情況下延遲過多的請求,則應該使用參數nodelay

舉個例子:

設置rate=20r/s每秒請求數為20個,burst為5個,burst是爆發的意思,這個配置的意思是設置一個大小為5的緩沖區當有大量請求(爆發)過來時,超過了訪問頻次限制的請求可以先放到這個緩沖區內等待,但是這個等待區里的位置只有5個,超過的請求會直接報503錯誤然后返回。

可能有幾個limit_req指令,例如,以下配置限制來自單個IP地址的請求的處理速率,同時限制虛擬服務器的請求處理速率,如下:

在http段寫入一下配置

limit_req_zone $binary_remote_addr zone=per_ip:10m rate=1r/s;

limit_req_zone $server_name zone=per_server:10m rate=10r/s;

在server段引用限制策略的名稱

limit_req zone=per_ip burst=5 nodelay;

limit_req zone=per_server burst=10;

配置說明:

burst=5:平均每秒最多允許不超過1個請求,並且突發不超過5個請求。

nodelay:如果設置,會在瞬時提供處理(burst + rate)個請求的能力,請求超過(burst + rate)的時候就會直接返回503,永遠不存在請求需要等待的情況。(這里的rate的單位是:r/s)如果沒有設置,則所有請求會依次等待排隊。

結束以后必須重啟Nginx或者重新加載配置文件才會生效

# 重啟Nginx

systemctl restart nginx

# 重新加載

nginx -s reload

這時配置就完成了,如果同一個IP在反復請求次數過於頻繁時,會怎么樣?下面測試

Nginx默認根目錄為:/usr/share/nginx/html/,在下面新建一個測試網頁:

vim /usr/share/nginx/html/nginx_limit.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Title</title>
</head>
<body>
<h2>Nginx訪問限制!</h2>
<img src="img/1.jpg">
</body>
</html>

在瀏覽器訪問:

Ctrl+F5連續多次刷新,在控制台出現503錯誤

也可以用壓力測試工具進行測試

# 安裝

yum install -y httpd-tools

# 測試

ab -n 100 -c 10 http://192.168.5.66/nginx_limit.html

其中,-n表示請求數,-c表示並發數

[root@CentOS7 ~]# ab -n 100 -c 10 http://192.168.5.66/nginx_limit.html
This is ApacheBench, Version 2.3 <$Revision: 1430300 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 192.168.5.66 (be patient).....done


Server Software: nginx/1.16.1
Server Hostname: 192.168.5.66
Server Port: 80

Document Path: /nginx_limit.html
Document Length: 250 bytes    # 文檔長度

Concurrency Level: 10    # 當前並發數
Time taken for tests: 5.003 seconds    # 消耗總時間
Complete requests: 100    # 完成請求數
Failed requests: 94    # 失敗請求數
(Connect: 0, Receive: 0, Length: 94, Exceptions: 0)
Write errors: 0
Non-2xx responses: 94    # 有問題的響應數
Total transferred: 67564 bytes    # 總的傳輸大小
HTML transferred: 47936 bytes    # http傳輸大小
Requests per second: 19.99 [#/sec] (mean)    # 每秒鍾處理多少個請求
Time per request: 500.281 [ms] (mean)
Time per request: 50.028 [ms] (mean, across all concurrent requests)
Transfer rate: 13.19 [Kbytes/sec] received

查看錯誤日志

tail -f /var/log/nginx/error.log

日志中會記錄下限制的請求

二、使用ngx_http_limit_conn_module模塊

ngx_http_limit_conn_module 模塊使用官方文檔:http://nginx.org/en/docs/http/ngx_http_limit_conn_module.html

ngx_http_limit_conn_module模塊用於限制單個IP地址的連接數

設置共享內存區域和給定鍵值的最大允許連接數。當超過此限制時,服務器將返回503(Service Temporarily Unavailable)錯誤 。

打開配置文件

vim /etc/nginx/nginx.conf

在http段寫入以下配置

limit_conn_zone $binary_remote_addr zone=conn_zone:10m;

配置說明:

設置共享內存區域名稱和大小。

定義一個名為conn_zone的limit_conn_zone用來存儲session,大小是10M內存,以變量 $binary_remote_addr 作為會話的判斷基准(即一個地址一個會話)。

$binary_remote_addr變量的大小對於IPv4地址總是4字節,對於IPv6地址總是16字節。存儲狀態在32位平台上總是占用32或64字節,在64位平台上占用64字節。當大小為1M的時候,可以保存大約3.2萬個32字節的狀態或大約1.6萬個64字節的狀態。

如果區域存儲耗盡,服務器將向所有后續請求返回503錯誤。

在location段引用

limit_conn conn_zone 1;

配置說明:

設置最大允許連接數。

conn_zone:要和http段中配置的zone=conn_zone策略名稱一致。

1:一個會話只能進行一個連接。 也就是,限制 / 目錄下,一次一個IP地址只允許一個連接,多過一個,一律503。

 

可能有幾個limit_conn指令,以下配置將限制每個客戶端IP與服務器的連接數,並同時限制與虛擬服務器的連接總數:

在http段寫入以下配置

limit_conn_zone $binary_remote_addr zone=per_ip:10m;

limit_conn_zone $server_name zone=per_server:10m;

在server段或者location段寫入以下配置

limit_conn per_ip 10;         # 單個客戶端IP與服務器的連接數

limit_conn per_server 100;  # 限制與服務器的連接總數

三、禁止IP或IP網段

查找服務器所有訪問者IP方法

awk '{print $1'} nginx_access.log |sort |uniq -c |sort -rn

nginx_access.log 為Nginx訪問日志文件所在路徑

會到如下結果,前面是IP的訪問次數,后面是IP,可以把訪問次數異常的IP屏蔽掉,如下面結果,

屏蔽IP的方法

ngx_http_access_module 模塊使用官方文檔:http://nginx.org/en/docs/http/ngx_http_access_module.html

在Nginx的配置文件目錄下面,新建屏蔽IP文件,命名為nginx_limit,以后新增加屏蔽IP只需編輯這個文件即可。

vim /etc/nginx/conf.d/nginx_limit

加入如下內容並保存:

deny 192.168.5.207;

在Nginx的配置文件default.conf中加入如下配置,可以放到http,server,location,limit_except語句塊,需要注意路徑,本例當中default.conf,nginx_limit在同一個目錄中。

include /etc/nginx/conf.d/nginx_limit;

保存default.conf文件,然后測試現在的nginx配置文件是否是合法的:

nginx -t

如果配置沒有問題,就會輸出:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

如果配置有問題就需要檢查下哪兒有語法問題,如果沒有問題,重啟 Nginx:

systemctl restart nginx

注意:

屏蔽IP的配置文件既可以屏蔽單個IP,也可以屏蔽IP段,或者只允許某個IP或者某個IP段訪問。

# 屏蔽單個IP訪問

deny IP;

# 允許單個IP訪問

allow IP;

# 屏蔽所有IP訪問

deny all;

# 允許所有IP訪問

allow all;

# 屏蔽整個段即從123.0.0.1到123.255.255.254訪問的命令

deny 123.0.0.0/8;

# 屏蔽IP段即從123.45.0.1到123.45.255.254訪問的命令

deny 124.45.0.0/16;

# 屏蔽IP段即從123.45.6.1到123.45.6.254訪問的命令

deny 123.45.6.0/24;

# 如果想實現這樣的應用,除了幾個IP外,其他全部拒絕,

# 那需要在 nginx_limit中這樣寫

allow 1.1.1.1;

allow 1.1.1.2;

deny all;

單獨網站屏蔽IP的方法,把 include /etc/nginx/conf.d/nginx_limit; 放到網址對應的在server{}語句塊,

所有網站屏蔽IP的方法,把 include /etc/nginx/conf.d/nginx_limit; 放到http {}語句塊。

四、阻止用戶使用代理

項目在上線之前,會對Nginx進行壓測。在真正上線以后,如果別人對服務器使用ab測試之類的,會對服務器有很大的風險。甚至就 curl 和 wget 都不想讓其用,只有正常的請求才可以使用。

Nginx提供了這樣的一個功能,拒絕用戶代理,這就需要使用到$http_user_agent變量。

下面三句if是禁止使用代理IP來訪問,或禁止使用壓力測試軟件進行DOS攻擊(放在default.conf的server里面)

    if ($http_user_agent ~* ApacheBench|WebBench|java/){ return 403; } if ($http_user_agent ~* (Wget|ab) ) { return 403; } if ($http_user_agent ~* LWP::Simple|BBBike|wget) { return 403; }

這些 if 聲明使用正則表達式匹配了任意不良用戶字符串,並向匹配的對象返回403 HTTP狀態碼。 $http_user_agent是HTTP請求中的一個包含有用戶代理字符串的變量。‘~’操作符針對用戶代理字符串進行大小寫敏感匹配,而‘~*’操作符則進行大小寫無關匹配。‘|’操作符是邏輯或,因此,你可以在 if 聲明中放入眾多的用戶代理關鍵字,然后將它們全部阻擋掉。

# 重啟nginx

systemctl restart nginx


免責聲明!

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



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