2011-11-05 34 views
3

我有一個不允許編輯iptables的虛擬主機。從時間上看,光(約300個請求/秒)拒絕服務攻擊(通常不分發)。我決定編寫一個PHP腳本來阻止這些ips。首先,我嘗試將最近10秒的所有請求存儲在數據庫中,並查找濫用每個請求的地址。但是我很快意識到,這種方式對於每個DoS請求都必須至少執行一次數據庫請求,並且它不好。然後我優化的這種做法如下:如何使用php檢測和禁止攻擊ips

Read 'deny.txt' with blocked ip's 
If it contains request ip, then die() 
--- at this point we have filtered out all known attacking ips --- 
store requesting ip in database 
clean all requests older than 10 secs 
count requests from this ip, if it is greater than threshold, add it to 'deny.txt' 

這樣,新的攻擊IP將只Threshold請求數據庫中,然後被阻斷。

因此,問題是,這種方法是否具有最佳性能?有沒有更好的方法來完成這項任務?

回答

2

這裏是我的代碼:

$ip = $_SERVER['REMOTE_ADDR']; 

// Log ip 
$query = "INSERT INTO Access (ip) VALUES ('$ip')";  
mysql_query($query) or HandleException("Error on logging ip access: " . mysql_error() . "; Query: " . $query); 

// Here should be database cleanup code 

// Count requests 
$query = "SELECT COUNT(*) FROM Access WHERE ip='$ip' AND time > SUBTIME(NOW(), '00:01:00')";   
$result = mysql_query($query) or HandleException("Error on getting ip access count: " . mysql_error() . "; Query: " . $query); 
$num = mysql_fetch_array($result); 
$accesses = $num[0]; 

// Ban ip's that made more than 1000 requests in 1 minute 
if($accesses > 1000) 
{ 
    file_put_contents('.htaccess', 'deny from ' . $ip . "\r\n", FILE_APPEND | LOCK_EX); 
} 

和存根的.htaccess:

order deny,allow 
deny from 111.222.33.44 
deny from 55.66.77.88 
3

嘗試使用Memcache,查找起來會快得多。

您可以使用密鑰的IP地址。閱讀價值。如果它不存在,則將其初始化爲0,如果它是數字,則將其增加。然後用1秒或10秒的TTL或任何你想要的時間回寫。如果計數高於閾值,則在TTL期間有很多請求,您可以阻止IP。

更新:我只是想通這將更新後的值將再次給它至少一秒鐘的新的TTL,這表明一個IP可能被阻塞,如果它是請求下一個剛剛連續間隔<threshold>請求第二個 ...
我不認爲它使這個答案完全無用,但是如果你想對我描述的文字實現的話,應該記住這一點。

阻塞可以永久完成(通過將其記錄到數據庫中)或更短的時間。您也可以使用MemCache,通過記錄標記(如'X')而不是計數器並將TTL設置爲更長的時間段。計數器腳本必須檢查讀取的值是不是'X',否則計數器將覆蓋該塊。

即使您想讓黑名單持續存在,我也會選擇使用Memcache。查找(您需要爲每個請求執行)要快得多。您可以將黑名單IP保存在數據庫中,並定期恢復該列表,或者至少在服務器重新啓動時恢復。這樣,您就擁有了一個持久的黑名單,而不必在每個請求上檢查數據庫。

+4

或者只是存儲永久黑名單成'.htaccess'文件。那麼PHP甚至不會再被那些困擾。 – hakre

+0

@GolezTrol非常好的建議,但不幸的是我沒有訪問memcached – Poma

+0

@hakre哇!這很可能會加速我的腳本。謝謝! – Poma