Nginx簡單防護CC攻擊

Nginx是一款輕量級的Web服務器,由俄羅斯的程序設計師Igor Sysoev所開發,最初供俄國大型的入口網站及搜尋引Rambler使用。 其特色是佔有內存少,併發能力強,事實上Nginx的併發能力確實在同類型的網站服務器中表現較好。 javascript

Nginx雖然能夠比Apache處理更大的鏈接數,可是HTTP GET FLOOD針對的不只僅是WEB服務器,還有數據庫服務器。大量HTTP請求產生了大量的數據庫查詢,能夠在幾秒以內使數據庫中止響應,系統負載升高,最終致使服務器當機。 php

本文主要介紹Centos+Nginx下如何快速有效得防護CC攻擊。至於如何安裝Nginx就不詳細介紹了,有興趣的讀者能夠在Nginx官方網站(http://www.nginx.org/)下載源代碼進行編譯。若是你使用的是Centos5,也可使用rpm包進行安裝(http://centos.alt.ru/repository/centos/5/i386/nginx-stable-0.7.65-1.el5.i386.rpm)。 html

1.        主動抑制
爲了讓Nginx支持更多的併發鏈接數,根據實際狀況對工做線程數和每一個工做線程支持的最大鏈接數進行調整。例如設置「worker_processes 10」和「worker_connections 1024」,那這臺服務器支持的最大鏈接數就是10×1024=10240。
worker_processes 10;
events {
use epoll;
worker_connections 10240;
} java

Nginx 0.7開始提供了2個限制用戶鏈接的模塊:NginxHttpLimitZoneModule和NginxHttpLimitReqModule。
NginxHttpLimitZoneModule能夠根據條件進行併發鏈接數控制。
例如能夠定義如下代碼:
http {
limit_zone   my_zone  $binary_remote_addr  10m;
server {
location /somedir/ {
limit_conn   my_zone  1;
}
}
}
其中「limit_zone  my_zone  $binary_remote_addr  10m」的意思是定義一個名稱爲my_zone的存儲區域、my_zone中的內容爲遠程IP地址、my_zone的大小爲10M;「location /somedir/」的意思是針對somedir目錄應用規則;「limit_conn  my_zone  1」的意思是針對上面定義的my_zone記錄區記錄的IP地址在指定的目錄中只能創建一個鏈接。 node

NginxHttpLimitReqModule能夠根據條件進行請求頻率的控制。
例如能夠定義如下代碼:
http {
limit_req_zone  $binary_remote_addr  zone=my_req_zone:10m   rate=1r/s;
...
server {
...
location /somedir/ {
limit_req   zone=my_req_zone  burst=2;
}
其中「limit_req_zone  $binary_remote_addr  zone=my_req_zone:10m  rate=1r/s」的意思是定義一個名稱爲my_req_zone的存儲區域,my_req_zone內容爲遠程IP地址,my_req_zone大小爲10M,my_req_zone中的平均請求速率只能爲1個每秒;「location /somedir/」的意思是針對somedir目錄應用規則;「limit_req_zone   zone= my_req_zone  burst=2」的意思是針對上面定義的my_req_zone記錄區記錄的IP地址在請求指定的目錄中的內容時最高2個每秒的突發請求速率。 mysql

當有鏈接觸發上訴規則時,Nginx會報「503 Service Temporarily Unavailable」的錯誤,中止用戶請求。返回一個503,對服務器來講影響不大,只佔用一個nginx的線程而已,相對來講仍是很划算的。 nginx

爲了測試效果,我將以上代碼放入Nginx的配置文件,並編寫了一個php文件顯示phpinfo;另外還寫了一個html文件,其中嵌入了多個iframe調用php文件。當我打開這個html文件了,能夠看到只有一個iframe中的php文件正常顯示了,其餘的iframe都顯示503錯誤。 web


應用舉例(Discuz!)
Discuz!是使用比較多的一個php論壇程序。以Discuz!7.0爲例,程序目錄下有比較多的能夠直接訪問的php文件,但其中最容易受到攻擊的通常有index.php(首頁)、forumdisplay.php(板塊顯示)、viewthread.php(帖子顯示)。攻擊者通常會對這些頁面發起大量的請求,致使HTTP服務器鏈接數耗盡、mysql數據庫中止響應,最終致使服務器崩潰。
爲了防止上述頁面被攻擊,咱們能夠設定如下的規則進行防護:
http {
limit_zone   myzone_bbs  $binary_remote_addr  10m;
limit_req_zone $binary_remote_addr zone=bbs:10m rate=1r/s;
...
server {
...
location ~ ^/bbs/(index|forumdisplay|viewthread).php$ {
limit_conn   myzone_bbs  3;
limit_req zone=bbs burst=2 nodelay;
root           html;
fastcgi_pass   unix:/dev/shm/php-cgi.sock;
fastcgi_index  index.php;
fastcgi_param  SCRIPT_FILENAME  /usr/share/nginx/html$fastcgi_script_name;
include        fastcgi_params;
}
}
}
應用這條規則後,bbs目錄下的index.php、forumdisplay.php和viewthread.php這些頁面同一個IP只許創建3個鏈接,而且每秒只能有1個請求(突發請求能夠達到2個)。
雖然這樣的規則通常來講對正常的用戶不會產生影響(極少有人在1秒內打開3個頁面),可是爲了防止影響那些手快的用戶訪問,能夠在nginx中自定義503頁面,503頁面對用戶進行提示,而後自動刷新。
在Nginx中自定義503頁面:
error_page   503   /errpage/503.html;
503頁面的源代碼:
<html>
< head>
< title>頁面即將載入....</title>
< meta http-equiv=content-type c>
< META NAME="ROBOTS" C>
< /head>
< body bgcolor="#FFFFFF">
< table cellpadding="0" cellspacing="0" border="0" width="700" align="center" height="85%">
<tr align="center" valign="middle">
<td>
<table cellpadding="10" cellspacing="0" border="0" width="80%" align="center" style="font-family:
Verdana, Tahoma; color: #666666; font-size: 11px">
<tr>
<td valign="middle" align="center" bgcolor="#EBEBEB">
<br /><b style="font-size: 16px">頁面即將載入</b>
<br /><br />你刷新頁面的速度過快。請少安毋躁,頁面即將載入...
<br /><br />[<a href="javascript:window.location.reload();"><font color=#666666>當即從新載入</font></a>]
<br /><br />
</td>
</tr>
</table>
</td>
</tr>
< /table>
< /body>
< /html> sql

< SCRIPT language=javascript>
function update()
{
window.location.reload();
}
setTimeout("update()",2000);
< /script> 數據庫

2.        被動防護
雖然主動防護已經抵擋了大多數HTTP GET FLOOD攻擊,可是道高一尺魔高一丈,攻擊者會總會找到你薄弱的環節進行攻擊。因此咱們在這裏也要介紹一下被動防護的一些方法。
1)        封IP地址
訪問者經過瀏覽器正常訪問網站,與服務器創建的鏈接通常不會超過20個,咱們能夠經過腳本禁止鏈接數過大的IP訪問。
如下腳本經過netstat命令列舉全部鏈接,將鏈接數最高的一個IP若是鏈接數超過150,則經過 iptables阻止訪問:
#!/bin/sh
status=`netstat -na|awk '$5 ~ /[0-9]+:[0-9]+/ {print $5}' |awk -F ":" -- '{print $1}' |sort -n|uniq -c |sort -n|tail -n 1`
NUM=`echo $status|awk '{print $1}'`
IP=`echo $status|awk '{print $2}'`
result=`echo "$NUM > 150" | bc`
if [ $result = 1 ]
then
echo IP:$IP is over $NUM, BAN IT!
/sbin/iptables -I INPUT -s $IP -j DROP
fi

運行crontab -e,將上述腳本添加到crontab每分鐘自動運行:
* * * * * /root/xxxx.sh
經過apache自帶的ab工具進行服務器壓力測試:
ab -n 1000 -c 100 http://www.xxx.com/bbs/index.php
測試完成後,咱們就能夠看到系統中有IP被封的提示:
[root@xxxxxx ~]#tail /var/spool/mail/root
Content-Type: text/plain; charset=ANSI_X3.4-1968
Auto-Submitted: auto-generated
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <HOME=/root>
X-Cron-Env: <;PATH=/usr/bin:/bin>
X-Cron-Env: <LOGNAME=root>
X-Cron-Env: <USER=root>

IP:58.246.xx.xx is over 1047, BAN IT!
至此,又一次HTTP GET FLOOD防護成功。

2)        根據特徵碼屏蔽請求(對CC攻擊效果較好)
通常同一種CC攻擊工具發起的攻擊請求包老是相同的,並且和正常請求有所差別。
當服務器遭遇CC攻擊時,咱們能夠快速查看日誌,分析其請求的特徵,好比User-agent。下面的是某一次CC攻擊時的User-agent
Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; MyIE 3.01)Cache-Control: no-store, must-revalidate
幾乎沒有正常的瀏覽器會在User-agent中帶上「must-revalidate」這樣的關鍵字。因此咱們能夠以這個爲特徵進行過濾,將User-agent中帶有「must-revalidate」的請求所有拒絕訪問:
if ($http_user_agent ~ must-revalidate) {
return 403;
}

本文主要介紹了nginx下的HTTP GET FLOOD防護,若是有不對的地方,但願你們能夠向我提出。同時,也但願你們可以觸類旁通,把這種思路應用到apache、lighttpd等常見的web服務器中。

相關文章
相關標籤/搜索