如何使用php检测和禁止攻击IP

如何使用php检测和禁止攻击IP,php,firewall,Php,Firewall,我有一个不允许编辑iptables的web主机。有时我会遇到轻微(约300个请求/秒)的DoS攻击(通常不分布)。我决定写一个PHP脚本来阻止这些IP。首先,我尝试将过去10秒的所有请求存储在数据库中,并查找每个请求的滥用地址。但我很快意识到,用这种方法,我必须为每个DoS请求至少向数据库发出一个请求,这是不好的。然后,我优化了该方法,如下所示: Read 'deny.txt' with blocked ip's If it contains request ip, then die() ---

我有一个不允许编辑iptables的web主机。有时我会遇到轻微(约300个请求/秒)的DoS攻击(通常不分布)。我决定写一个PHP脚本来阻止这些IP。首先,我尝试将过去10秒的所有请求存储在数据库中,并查找每个请求的滥用地址。但我很快意识到,用这种方法,我必须为每个DoS请求至少向数据库发出一个请求,这是不好的。然后,我优化了该方法,如下所示:

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
请求,然后被阻止


所以,问题是,这种方法是否具有最佳性能?有更好的方法来完成这项任务吗?

尝试使用Memcache,它会更快地查找

您可以使用IP地址作为密钥。读取值。如果它不存在,则将其初始化为0,如果它是一个数字,则将其递增。然后用1秒或10秒的TTL或任何你想要的时间段写回来。如果计数高于阈值,则在TTL期间有到多个请求,您可以阻止IP

更新:我只是想,设置更新的值将再次给它一个至少1秒的新TTL,因此,如果IP以不到1秒的连续间隔请求
请求,它可能会被阻止
我不认为这会使这个答案完全无用,但如果你想对我描述的内容进行文字化的实现,就要记住这一点

阻塞可以永久地(通过将其记录到数据库中)完成,也可以在更短的时间内完成。您也可以使用MemCache,通过记录一个标记(如“X”)而不是一个计数器,并将TTL设置为更长的周期。计数器脚本必须检查读取值是否不是“X”,否则计数器将覆盖块

我会选择使用Memcache,即使你想让黑名单持久化。查找(您需要为每个请求执行)要快得多。您可以在数据库中保存列入黑名单的IP,并定期或至少在服务器重新启动时恢复该列表。这样,您就得到了一个持久的黑名单,而无需在每次请求时检查数据库。以下是我的代码:

$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

或者将永久黑名单存储到
.htaccess
文件中。这样PHP就不会再被这些问题困扰了。@GolezTrol非常好的建议,但不幸的是我无法访问memcached