Pull to refresh

Простейшая защита от DDOS на PhP

Многие задаются вопросом, возможно ли бороться с DDOS при помощи PhP? Казалось бы, ответ очевиден — нет. Другие скажут, что это полнейший бред и не нужно страдать ерундой. Я, конечно же, никого переубеждать не стану. Однако, хотелось бы рассказать о своем подходе к решению этой столь нетривиальной задачи.

Перед тем, как меня вот-вот закидают камнями, хотелось бы отметить, что данный пример не применим к использованию на high-load серверах, которые могут подвергаться или подвергаются сильным ддос атакам. Так как в этом случае, Вам нужны более серьезные методы решения данной проблемы. (Возможно в дальнейшем, я расскажу о некоторых из них) Это скорей игрушка для вашего блога. Однако, как показала практика, эта штука, что-то, все-таки умеет.

Ничего сверхъестественного для работы скрипта нам не понадобиться: iptables и, непосредственно, сам php интерпретатор.
Собственно, код скрипта довольно простой, поэтому в особых комментариях не нуждается:

$config     = 'conf.ini';
$config     = parse_ini_file($config, true);

/** некоторые настройки php, для localhost **/
header('Content-Type: text/plain; charset=UTF-8');
ob_implicit_flush(); 
set_time_limit(0);

$skip = array();
$data = array();

while(true): /* По желанию, можно запускать из крона */
$content    = $config['logs']['use'] == 'file' ? file($config['logs']['file'])
                                               : explode("\n", shell_exec($config['logs']['command']));

/**
 * Функция проверяет значение максимального лимита для заданного ip на какой-либо параметр
 * @param   string  $e      параметр
 * @param   string  $ip     ip
 */
 
function check($e, $ip){
    global $data, $config, $skip;
    $ipdata = $data[$ip][$e];
    if(($d = count($ipdata)) >= $config['block']['max_' . $e]){
        block($ip, 'max_' . $e . '=' . $config['block']['max_' . $e]);
        $skip[] = $ip;
    }
}

/**
 * Функция блокирования ip
 * @param   string  $ip ip
 */
function block($ip, $r = false){
    print "block: {$ip}" . ($r !== false ? ", $r" : '') . "\n";
    shell_exec('/sbin/iptables -I INPUT -j DROP -s ' . $ip);
    file_put_contents('/a/' . date('d-m-Y') . '.log', "{$ip}\n", FILE_APPEND);
}


/**
 * Возвращает массив с распознанными данными.
 * @param   string  $line
 * @return  array
 */
function recognize($line){
    while(strstr($line, '[[') || strstr($line, ']]'))
        $line = str_replace(array(']]', '[['), array(']', '['), $line);

    preg_match_all('|\-([a-z]{1,})\[(.*)]|U', $line, $arr);
    $recognize = array();
    foreach($arr[1] AS $i => $j){
        $recognize[$j] = $arr[2][$i];
    }
    return (array) $recognize;
}


foreach($content AS $line){
    $request = recognize($line);
    if(!isset($request['ip'])){
        continue;
    }

    if(in_array($request['ip'], $skip)){
        unset($data[$request['ip']]);
        continue;
    }
    
    if(!isset($data[$request['ip']])){
        $data[$request['ip']] = array('ua' => array(), 'referer' => array());
    }
        
    if($request['ua'] == '' || $request['ua'] == '-'
    || $request['referer'] == '' || $request['referer'] == '-'){
        if(strtoupper($config['block']['empty']) == 'ON'){
            block($request['ip']); continue;    
        }
    } 
    if($request['ua'] = trim($request['ua'])){
        if(! in_array($request['ua'], $data[$request['ip']]['ua'])){
            
            $data[$request['ip']]['ua'][] = $request['ua'];
            if(check('ua', $request['ip']))
                continue;
        }
    }
    
    $referer = @parse_url($request['referer']);
    if($referer['host'] = trim($referer['host']) && $referer['host'] != $request['host']){
        if(! in_array($referer['host'], $data[$request['ip']]['referer'])){ 
            $data[$request['ip']]['referer'][] = $referer['host'];
            check('referer', $request['ip']);
        }    
    }
}
sleep(1);
endwhile;


И, конечно же, конфиг файл к скрипту. Так же, ничего особенного.

[logs]
;команда для получения логов
;command  = "cat /var/log/* | grep 192.168.15.7"
command  = "cat logs/deweber.org.acc_log * | grep 192.168.15.7" 
;файл с логами
file  = "httpd-traffic.log"
;доставать логи из файла или выполнять команду
;command/file
use   =  "command"
[ban]
empty  =  On
max_ua  =  5
max_referer = 10


Запускать можно по крону. Либо как вариант:

/usr/bin/php -dsafe_mode=Off -ddisable_functions= -dallow_url_fopen=On /root/tools/antiddos.php > /dev/null &

На этом, моя первая статья закончена. Прошу прощения за возможные синтаксические или пунктуационные ошибки. Хотелось бы услышать Ваше мнение, по поводу моих не всегда умных мыслей.
Всем спасибо.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.