我有一个不允许编辑iptables的虚拟主机。从时间到我有轻量级(约300请求/秒)DoS攻击(通常不分发)。我决定编写一个可以阻止这些ips的PHP脚本。首先,我尝试将所有最近10秒的请求存储在数据库中,并查找滥用每个请求的地址。但我很快意识到,这样我每次DoS请求都必须至少向数据库发出1个请求,这并不好。然后我优化了这种方法如下:
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
个请求,然后被阻止。
所以,问题是,这种方法是否具有最佳性能?有没有更好的方法来完成这项任务?
答案 0 :(得分:3)
尝试使用Memcache,查找速度会快得多。
您可以使用密钥的IP地址。读取值。如果它不存在,则将其初始化为0,如果是数字,则将其递增。然后使用1秒或10秒的TTL或任何您想要的时间将其写回。如果计数高于阈值,则在TTL期间会有许多请求,您可以阻止IP。
更新:我只是认为设置更新后的值会再次给它一个至少一秒的新TTL,因此如果要请求 <threshold>
<,则可以阻止IP em>请求以不到一秒的连续间隔 ...
我不认为它会使这个答案完全无用,但如果你想对我所描述的内容进行文字实现,那就要记住了。
可以永久阻止(通过将其记录在数据库中)或更短的时间段进行阻止。您也可以通过记录标记(如“X”)而不是计数器来使用MemCache,并将TTL设置为更长的时间段。计数器脚本必须检查读取值是否为“X”,否则计数器将覆盖该块。
我会选择使用Memcache,即使你想让黑名单持久化。查找(您需要为每个请求执行)要快得多。您可以将列入黑名单的IP保存在数据库中,并定期还原该列表,或者至少在重新启动服务器时还原该列表。这样,你就得到了一个持久的黑名单,而不必在每次请求时都检查数据库。
答案 1 :(得分: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