简体   繁体   English

PHP,.htaccess,DDoS和快速请求保护

[英]PHP, .htaccess, DDoS & speedy request protection

I have a question, i built this little script to check if a certain ip is flooding my website. 我有一个问题,我建立了这个小脚本来检查某个IP是否淹没了我的网站。 When it does, i deny the ip in the .htaccess file. 这样做时,我拒绝.htaccess文件中的IP。 My question is, can somebody tell me if this script is completely useless or worth trying... The script is called in the config file therefore it runs on every pageload. 我的问题是,有人可以告诉我此脚本是否完全没用或值得尝试...该脚本在配置文件中调用,因此它在每个页面加载时运行。

<?php
#get the visitor ip
$ip = $_SERVER["REMOTE_ADDR"];

#start the session
@session_start();

#check if the ip is banned
if( $_SESSION['~b'] ){

#check if we can open htaccess
$fp = @fopen('./.htaccess','a'); 
    if($fp){
        #add the ip to htaccess
        @fwrite($fp,"\r\ndeny from $ip"); 
        #close
        @fclose($fp);
        #destroy the session
        @session_destroy();
        @mail("my-email","IP Banned","Ip: $ip");
    }
    #let the user know why we deny him or her access
    die('To many requests.');
    }
#get the filename and location
$f = './log/'.@ip2long($ip);

#check if the file exists
if ( @is_file($f) ) {
        #get the last filetime
        $a = @filemtime($f);
        #touch the file, give a new filetime
        @touch($f,time());
        #the ip is not banned
        $_SESSION['~b']  = false;
        #add the time diff
        $_SESSION['~r'] += @time()-$a;
        #add the latest hit
        $_SESSION['~h'] += 1;
    }else{
        #create the file if it doesn't exist
        @file_put_contents($f,''); #size: 0kb
        #if touch() doesn't work
        #chmod($ipfile,0755); 
    }

#calculate the diff after 10 hits, and ban when the avg is smaller than 0.25 seconds
if( $_SESSION['~h'] > 10 && ($_SESSION['~r']/$_SESSION['~h']) < 0.25 ) $_SESSION['~b'] = true;
?>

Just followed the advice to avoid SESSIONS, so i made it file based, without having to be depending on cookies and session: 只是遵循了避免会话的建议,所以我使它基于文件,而不必依赖Cookie和会话:

<?php
# get the visitor ip
$i = $_SERVER["REMOTE_ADDR"];
# get the filename and location
$f = './log/'.ip2long($i).'.dat';
# check if the file exists and we can write
if ( is_file($f) ) {
    # get the last filetime
    $a = filemtime($f);
    # get the file content
    $b = file_get_contents($f);
    # create array from hits & seconds
    $d = explode(':',$b);
    # calculate the new result
    $h = (int)$d[0] + 1;
    $s = (int)$d[1] + (time()-$a);  
    # add the new data tot text file
    file_put_contents($f,"$h:$s",LOCK_EX);
    unset($d);
}else{
    # create the file if it doesn't exist hits:seconds
    file_put_contents($f,"1:1",LOCK_EX); #size: 3kb
    # to make sure we can write
    # chmod($f,0755); 
    # set the hits to zero
    $h = 0;
}
# create a result var
$r = $h > 10 ? (float)$s/$h : (float)1;
# calculate the diff after 10 hits, and ban when the avg is smaller than 0.20 seconds (5 hits per second)
if( $r < 0.20 ) {
    # check if we can open htaccess
    $fp = @fopen('./.htaccess','a'); 
    if($fp){
        # add the ip to htaccess
        @fwrite($fp,"\r\ndeny from $i"); 
        # close
        @fclose($fp);
        # mail the admin
        @mail("email","IP Banned","Ip: $i with $r sbh (Seconds Between Hits)");
    }
    # let the user know why we deny him or her access
    die('To many requests.');
    # remove the file
    unlink($f);
}
# if the user leaves, reset
if( $r > 30 ) {
    unlink($f);
}
echo 'Result: '.$r.'sbh (Seconds Between Hits)';
?>

If you want to stop the casual user from sending too many requests in a certain amount of time, then yes , the script could work. 如果要阻止临时用户在一定时间内发送太多请求,则可以 ,该脚本可以工作。 Bring up a catpcha screen and you're in business. 弹出一个catpcha屏幕,您可以开展业务。

BUT

The real answer is no . 真正的答案是否定的

The primary mistake with this code is depending on a session to determine the frequency of the user's activity. 此代码的主要错误取决于确定用户活动频率的会话。 A "good" attacker can flood your server with requests with cookies disabled, as well as spoof his/her IP. 一个“好的”攻击者可以使用禁用了Cookie的请求充斥您的服务器,并欺骗其IP。

One way to stop attacks is to go to the server level, and install iptables. 阻止攻击的一种方法是进入服务器级别,并安装iptables。 In fact, iptables ships with most linux distros. 实际上,大多数Linux发行版都附带iptables。 It needs little configuration and works well out of the box. 它几乎不需要配置,开箱即用。

Another way, if you have root access to your server, is to move session handling to Memcached. 如果您具有对服务器的root访问权,另一种方法是将会话处理移至Memcached。 It has a function called flood control that is pretty BOSS. 它具有一个称为洪水控制的功能,非常漂亮。

Another route to prevent DDOS are from third party services such as blockdos http://www.blockdos.net/ 防止DDOS的另一种途径是来自第三方服务,例如blockdos http://www.blockdos.net/

Kinda pricey, but it could work for you. 有点昂贵,但它可以为您工作。

But PHP by itself cannot be configured to handle DDOS attacks. 但是PHP本身无法配置为处理DDOS攻击。 You need to put some kind of appliance or firewall in front of all requests to be vetted before going to your PHP scripts. 在转到PHP脚本之前,需要在所有要审核的请求之前放置某种设备或防火墙。

My two cents. 我的两分钱。 It is a good idea however you might end up stopping legitimate users from accessing your website. 这是一个好主意,但是您最终可能会阻止合法用户访问您的网站。 It will also be a problem with bots such as the Google bot. 诸如Google机器人之类的机器人也会出现问题。 As such I would be careful. 因此,我会小心。 Perhaps also check the user agent and if it comes up as Google then allow it regardless of other conditions. 也许还要检查用户代理,如果它作为Google出现,则无论其他条件如何都允许它。 Of course this then opens up a new hole for malicious users. 当然,这为恶意用户打开了一个新漏洞。 Normally things like this are done on the web server rather than with PHP code. 通常,类似的事情是在Web服务器上完成的,而不是使用PHP代码。 Another approach is the token system. 另一种方法是令牌系统。 That said, I think with some further refinement you could be onto something with your approach. 就是说,我认为通过进一步完善,您可以采用自己的方法。

Also have you seen .htaccess or PHP protection code against multiple speedy requests question? 您还看到针对多个快速请求的.htaccess或PHP保护代码问题吗? It suggests that what you are designing has been tried before. 这表明您已经在尝试设计。 This tells you are probably heading in the right direction. 这表明您可能正在朝正确的方向前进。

Mitigating DDoS by setting request-rate based IP blocking rules will always end badly, because: 通过设置基于请求速率的IP阻止规则来缓解DDoS总是很糟糕,因为:

  1. such rules will affect legitimate users (false positives) 此类规则将影响合法用户(误报)
  2. for IP spoofing, it is very common that this will not work against most, if not all attackers. 对于IP欺骗,很常见的做法是,即使不是所有攻击者,它也无法对大多数攻击者起作用。

This is also true for IPTables. 对于IPTables也是如此。 You can learn more about it here: http://www.incapsula.com/ddos/ddos-protection-service#iptables-ddos-protection 您可以在此处了解更多信息: http : //www.incapsula.com/ddos/ddos-protection-service#iptables-ddos-protection

The solution is quite helpful. 该解决方案非常有帮助。 Meanwhile, regarding the question asked by @lopata you may rather comment out the unlink() functions in the script and set-up a cron-job that will be unblocking the IPs from the htaccess and removing the files after sometime. 同时,关于@lopata提出的问题,您可能宁愿注释掉脚本中的unlink()函数,并设置cron-job,以便在一段时间后取消htaccess中的IP并删除文件。

<?php

function unban_ip($ip){
    $filename='.htaccess';
    $line="deny from $ip";
    file_put_contents($filename, str_replace("\r\n".$line, "", file_get_contents($filename)));
    $f = './log/'.@ip2long($ip);
    if(@is_file($f))unlink($f);
    return true;
}

$time=time();   
$path='./log';
$handle=@opendir($path);
$x=0;

while(($file=@readdir($handle))!==false){
    if($file=='.'||$file=='..')continue;
    $filepath="$path/$file";

    if(is_file($filepath)){
        $ftime=@filemtime($filepath);
        if($time-$ftime>600){  //unban after 10 minutes
            $ip=long2ip($file);
            unban_ip($ip);
            $x++;
        }
    }
}

echo "$x IPs Unbanned";

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM