2011-11-05 66 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