最近一直在幫一個購買了張戈博客付費服務的朋友做網站防護,為了簡單抵擋一下競爭對手的DDoS攻擊,他給網站開啟了Incapsula的免費CDN服務。
開啟CDN之后,我之前給他寫的Shell防護腳本也就宣告無效了,因為不管是正常訪問還是攻擊訪問,腳本拿到的IP都是CDN節點的,而我不可能把CDN的節點IP也給禁用了,那就都不能訪問了。
為了解決這個窘迫,我想到了以前看過的Nginx訪問限制。通過查資料,讓我拜讀了一枚大神的神作,感覺收獲頗豐!於是轉過來整理一下,分享給更多需要的人!
Nginx 有2個模塊用於控制訪問“數量”和“速度”,簡單的說,控制你最多同時有 多少個訪問,並且控制你每秒鍾最多訪問多少次, 你的同時並發訪問不能太多,也不能太快,不然就“殺無赦”。
HttpLimitZoneModule 限制同時並發訪問的數量
HttpLimitReqModule 限制訪問數據,每秒內最多幾個請求
一、普通配置
什么叫普通配置?
普通配置就是針對【用戶瀏覽器】→【網站服務器】這種常規模式的nginx配置。那么,如果我要對單IP做訪問限制,絕大多數教程都是這樣寫的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
## 用戶的 IP 地址 $binary_remote_addr 作為 Key,每個 IP 地址最多有 50 個並發連接
## 你想開 幾千個連接 刷死我? 超過 50 個連接,直接返回 503 錯誤給你,根本不處理你的請求了
limit_conn_zone $binary_remote_addrzone=TotalConnLimitZone:10m;
limit_conn TotalConnLimitZone50;
limit_conn_log_level notice;
## 用戶的 IP 地址 $binary_remote_addr 作為 Key,每個 IP 地址每秒處理 10 個請求
## 你想用程序每秒幾百次的刷我,沒戲,再快了就不處理了,直接返回 503 錯誤給你
limit_req_zone $binary_remote_addrzone=ConnLimitZone:10mrate=10r/s;
limit_req_log_level notice;
## 具體服務器配置
server{
listen80;
location~\.php${
## 最多 5 個排隊, 由於每秒處理 10 個請求 + 5個排隊,你一秒最多發送 15 個請求過來,再多就直接返回 503 錯誤給你了
limit_req zone=ConnLimitZone burst=5nodelay;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
}
}
|
這樣一個最簡單的服務器安全限制訪問就完成了,這個基本上你 Google 一搜索能搜索到 90% 的網站都是這個例子,而且還強調用“$binary_remote_addr”可以節省內存之類的雲雲。
二、CDN之后
目前國內已經爭相出現了百度雲加速、加速樂、360網站衛士以及安全寶等免費CDN。讓我們這些小網站也能免費享受以前高大上的CDN加速服務。
於是,網站的訪問模式就變為:
用戶瀏覽器 → CDN節點 → 網站源服務器
甚至是更復雜的模式:
用戶瀏覽器 → CDN節點(CDN入口、CC\DDoS攻擊流量清洗等) → 阿里雲盾 → 源服務器
可以看到,我們的網站中間經歷了好幾層的透明加速和安全過濾, 這種情況下,我們就不能用上面的“普通配置”。因為普通配置中基於【源IP的限制】的結果就是,我們把【CDN節點】或者【阿里雲盾】給限制了,因為這里“源IP”地址不再是真實用戶的IP,而是中間CDN節點的IP地址。
我們需要限制的是最前面的真實用戶,而不是中間為我們做加速的加速服務器。
其實,當一個 CDN 或者透明代理服務器把用戶的請求轉到后面服務器的時候,這個 CDN 服務器會在 Http 的頭中加入一個記錄
X-Forwarded-For : 用戶IP, 代理服務器IP
如果中間經歷了不止一個代理服務器,這個記錄會是這樣
X-Forwarded-For : 用戶IP, 代理服務器1-IP, 代理服務器2-IP, 代理服務器3-IP, ….
可以看到經過好多層代理之后, 用戶的真實IP 在第一個位置, 后面會跟一串中間代理服務器的IP地址,從這里取到用戶真實的IP地址,針對這個 IP 地址做限制就可以了。
那么針對CDN模式下的訪問限制配置就應該這樣寫:
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
|
## 這里取得原始用戶的IP地址
map$http_x_forwarded_for$clientRealIp{
""$remote_addr;
~^(?P<firstAddr>[0-9\.]+),?.*$$firstAddr;
}
## 針對原始用戶 IP 地址做限制
limit_conn_zone $clientRealIpzone=TotalConnLimitZone:20m;
limit_conn TotalConnLimitZone50;
limit_conn_log_level notice;
## 針對原始用戶 IP 地址做限制
limit_req_zone $clientRealIpzone=ConnLimitZone:20mrate=10r/s;
#limit_req zone=ConnLimitZone burst=10 nodelay; #如果開啟此條規則,burst=10的限制將會在nginx全局生效
limit_req_log_level notice;
## 具體Server:如下在監聽php部分新增限制規則即可
server{
listen80;
location~\.php${
## 最多 5 個排隊, 由於每秒處理 10 個請求 + 5個排隊,你一秒最多發送 15 個請求過來,再多就直接返回 503 錯誤給你了
limit_req zone=ConnLimitZone burst=5nodelay;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
}
}
|
三、echo模塊
作者原文提到了nginx的一個echo模塊,特意玩了下感覺挺有意思的,下面貼一下簡單集成步驟。
①、給nginx集成echo模塊:
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
|
cd/usr/local/src
#下載echo模塊並解壓:
wget https://github.com/openresty/echo-nginx-module/archive/v0.57.tar.gz
tar zxvf v0.57.tar.gz
#下載nginx並解壓
wget http://nginx.org/download/nginx-1.6.0.tar.gz
tar-xzvf nginx-1.6.0.tar.gz
cdnginx-1.6.0/
#查看在用nginx的編譯參數(如果是全新安裝則省略)
/usr/local/nginx/sbin/nginx-V
nginx version:nginx/1.6.0
built by gcc4.4.720120313(Red Hat4.4.7-4)(GCC)#以下這行即為舊的編譯參數:
configure arguments:--user=www--group=www--prefix=/usr/local/nginx--with-http_gzip_static_module
#在舊的編譯參數基礎上新增【--add-module=/echo模塊的解壓路徑】參數,開始編譯
./configure--prefix=/usr/local/nginx/nginx--add-module=/usr/local/src/echo-nginx-module-0.57
#make編譯
make-j2
#平滑升級nginx (如果是全新安裝請執行:make install)
mv/usr/local/nginx/sbin/nginx/usr/local/nginx/sbin/nginx.old
cp-fobjs/nginx/usr/local/nginx/sbin/
makeupgrade
|
②、echo用法舉例:
其實就和shell的echo差不多,能否輸出自定義信息。
比如,在nginx里面配置如下:
1
2
3
|
location/hello{
echo"hello, world!";
}
|
訪問http://yourdomain.com/hello 就會在瀏覽器里面輸出hello, world! 了(如果域名開了CDN可能會報404)。
又比如,測試本文提到的真實用戶的IP,只要在本文第二步配置基礎上,加上如下規則並reload即可:
1
2
3
4
5
6
7
8
9
10
|
server{
listen80;
server_name yourdomain.com;
## 以下是新增規則:
## 當用戶訪問 /realip 的時候,我們輸出 $clientRealIp 變量,看看這個變量
## 值是不是真的 用戶源IP 地址
location/realip{
echo$clientRealIp;
}
}
|
生效后,訪問http://yourdomain.com/realip 就能顯示你所用電腦(寬帶)的真實IP了(可在ip138查驗准確性):
Ps:感興趣又喜歡學習的童鞋可以看下相關wiki文檔:http://wiki.nginx.org/HttpEchoModule
本文介紹到這就差不多結束了,也是在神作的基礎上精簡整理並測試的,如果看完還有些許疑問,請前往查看神作原文,也許還是大神寫的比較好理解(是否是原創我就不深究了,感覺也是轉來轉去,都沒留鏈接,悲哀的互聯網)!
本文整理自【棒主婦開源】,原文地址:《網站安全配置(Nginx)防止網站被攻擊》。