На уровне PHP защищаться от ддоса не эффективно, такие скрипты применяют на хостинг-тарифах, где нет возможности конфигурации сервера. Впрочем, хостеры обычно отключают сайт, если на него идет ДДос, поэтому никакие скрипты вы использовать не успеете.
Выкладываю некоторые здесь. Если кому помогут - отписывайтесь, вместе посмеемся над этим ддосером.
Но прежде чем использовать подобные скрипты, надо оценить обстановку.
Если ваш хостер предоставляет SSH-доступ, попробуйте с помощью команды
netstat -ntu |wc -l
определить силу ддоса. Команда выведет количество соединений. Если сервер совсем повис, попробуйте перезагрузить его (через службу поддержки или самостоятельно если такая возможность есть) и отрубите апач
service httpd stop
если у вас nginx
service nginx stop
либо, если ддос несильный, закоментируйте срочку _index.php в корне вашего сайта. После чего можно поизучать логи и оценить силу и таргетинг ддоса.
Если ддос действительно слабенький, можно попробовать использовать PHP скрипты, но предупреждаю, они будут загружать сервер и годятся только как временное решение проблемы.
Скрипт AntiOverload *FIX*
<?php /* *-------------------------------------------------------- * Модуль antioverload *-------------------------------------------------------- * Модуль предназначен для ограничения доступа к сайту или * к страницам, где он включён. * Принцип работы в том, что запоминается ip-адрес и время * обращения с этого адреса. И если в течение заданного * времени происходит обращение с того же адреса, то ему * выдаётся ошибка 503. * Модуль необходимо подключать к скрипту самым первым. * Этим обеспечивается быстрота его работы. *-------------------------------------------------------- */ /* Время задержки в секундах */ $ad_delay=2; /* Путь к папке с временными файлами. Должен существовать */ $ad_DirName=$_SERVER['DOCUMENT_ROOT'].'/tmp'; /* *--------------------------------------------------------- * Список поисковых роботов. * Очень не хорошо, если поисковый робот будет натыкаться * на ошибки на сайте. Ему это может сильно не понравиться. * Поэтому пишем список юзер-агентов роботов; добавляем или * удаляем, что нужно. *--------------------------------------------------------- */ $ad_Robots_UserAgent=array( 'aipbot', 'Aport', 'eStyleSearch', 'Gigabot', 'Gokubot', 'Google', 'MJ12bot', 'msnbot', 'PlantyNet_WebRobot', 'StackRambler', 'TurtleScanner', 'Yahoo', 'Yandex', 'YaDirectBot', ); /* *--------------------------------------------------------- * Список доверенных IP. *--------------------------------------------------------- */ $ad_good_ip = array( '217.107.36.73', ); /* *---------------------------------------------------------- * Функция создаёт в указанной директории файл, начинающийся * с буквы a (для отличия от других возможных файлов) и * содержащий в имени ip-адрес клиента. *---------------------------------------------------------- */ function ad_WiteIP($dir){ $f=fopen($dir.'/a'.$_SERVER['REMOTE_ADDR'], 'w'); fclose($f); } /* *---------------------------------------------------------- * Проверка на наличие в поле HTTP_USER_AGENT чего-нибудь из * вышенаписанного списка. *---------------------------------------------------------- */ $ad_IsRobot=false; foreach ($ad_Robots_UserAgent as $match){ if (strstr($_SERVER['HTTP_USER_AGENT'], $match)){ $ad_IsRobot=true; break; } } if( in_array($_SERVER['REMOTE_ADDR'], $ad_good_ip) ) { $good_ip = true; } else { $good_ip = false; } /* *--------------------------------------------------------- * Поисковые роботы не любят, когда к адресу страницы * добавляется переменная сессии. Поэтому, если на сайте * используются сессии, то их лучше включать, если агент - * не робот. * Если сессии не используются, то этот кусок можно убрать. *--------------------------------------------------------- */ if (!$ad_IsRobot AND !$good_ip){ session_start(); } if (!$ad_IsRobot AND !$good_ip){ /*** Чтение каталога и удаление старых файлов ***/ $ad_dir =opendir($ad_DirName) or die('Отсутствует директория для временных файлов'); $ad_now =time(); $ad_forbid =$ad_now-$ad_delay; /* IP-адрес в имени файла, начинающегося на букву a, а время обращения - время изменения файла */ while (false!==($ad_FName=readdir($ad_dir))){ if (ereg('^a[1-9]',$ad_FName) && (@ filemtime($ad_DirName.'/'.$ad_FName)<$ad_forbid)){ @ unlink($ad_DirName.'/'.$ad_FName); } } closedir($ad_dir); /*** Проверка на существование пометки о недавнем обращении с данного ip-адреса ***/ if (file_exists($ad_DirName.'/a'.$_SERVER['REMOTE_ADDR'])){ /* Если обращение было недавно, то выводим сообщение об ошибке */ header('HTTP/1.0 503 Service Unavailable'); header('Status: 503 Service Unavailable'); header('Retry-After: '.$ad_delay*3); ?> <!doctype html public "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <title>Ошибка 503</title> <meta http-equiv="Content-Type" content="text/html; charset=Windows-1251" /> </head> <body> <h1>Ошибка 503 (Service Unavailable)</h1> <p>Сервер не может в данный момент выдать запрашиваемую Вами страницу. Попробуйте вызвать эту страницу позже (клавиша F5).</p> </body> </html> <?php ad_WiteIP($ad_DirName); // Перед выходом записываем ip exit; }else{ ad_WiteIP($ad_DirName); } } ?>
Антиддос скрипт от админа xaknet.ru:
<?php class antiDdos { // дебаг public $debug = false; // директория для хранения файлов индефикации запросов public $dir = '_bots/'; // номер icq администратора public $icq = '123456'; // сообщение при выключенном сайте public $off_message = 'Временные неполадки, пожалуйста, подождите.'; // индивидуальный индефикатор private $indeficator = null; // сообщение при бане, работают шаблоны, можно использовать - {ICQ}, {IP}, {UA}, {DATE} public $ban_message = 'Вы были заблокированы antiddos системой. Если это ошибка обратитесь к администратору, icq of admin: {ICQ} <hr>(c)XakNet antiddos module, ваш IP - {IP}(<i>{UA}</i>), date - {DATE}'; // команда выполнения бана в файрволле public $exec_ban = 'iptables -A INPUT -s {IP} -j DROP'; // тип защиты от ддоса: /* Возможные значения $ddos 1-5: | 1. Простая проверка по кукам, по умолчанию(рекомендую) | 2. Двойная проверка через $_GET antiddos и meta refresh | 3. Запрос на авторизацию WWW-Authenticate | 4. полное отключение сайта, боты не блокируются!!! | 5. выключать сайт если нагрузка слишком большая на сервере, боты не блокируются!!! */ var $ddos = 1; // часть домена поисковых ботов, см strpos() private $searchbots = array('googlebot.com', 'yandex.ru', 'ramtel.ru', 'rambler.ru', 'aport.ru', 'sape.ru', 'msn.com', 'yahoo.net'); // временная переменные нужные для работы скрипта private $attack = false; private $is_bot = false; private $ddosuser; private $ddospass; private $load; public $maxload = 80; function __construct($debug) { @session_start() or die('session_start() filed!'); $this->indeficator = md5(sha1('botik' . strrev(getenv('HTTP_USER_AGENT')))); $this->ban_message = str_replace(array('{ICQ}', '{IP}', '{UA}', '{DATE}'), array($this->icq, $_SERVER['REMOTE_ADDR'], $_SERVER['HTTP_USER_AGENT'], date('d.m.y H:i')), $this->ban_message ); if (eregi(ip2long($_SERVER['REMOTE_ADDR']), file_get_contents($this->dir . 'banned_ips'))) die($this->ban_message); $this->exec_ban = str_replace('{IP}', $_SERVER['REMOTE_ADDR'], $this->exec_ban); $this->debug = $debug; if(!function_exists('sys_getloadavg')) { function sys_getloadavg() { return array(0,0,0); } } $this->load = sys_getloadavg(); if(!$this->sbots()) { $this->attack = true; $f = fopen($this->dir . ip2long($_SERVER["REMOTE_ADDR"]), "a"); fwrite($f, "query\n"); fclose($f); } } /** * Старт работы антиддоса **/ function start() { if($this->attack == false) return; switch($this->ddos) { case 1: $this->addos1(); break; case 2: $this->addos2(); break; case 3: $this->ddosuser = substr(ip2long($_SERVER['REMOTE_ADDR']), 0, 4); $this->ddospass = substr(ip2long($_SERVER['REMOTE_ADDR']), 4, strlen(ip2long($_SERVER['REMOTE_ADDR']))); $this->addos3(); break; case 4: die($this->off_message); break; case 5: if ($this->load[0] > $this->maxload) { header('HTTP/1.1 503 Too busy, try again later'); die('<center><h1>503 Server too busy.</h1></center><hr><small><i>Server too busy. Please try again later. Apache server on ' . $_SERVER['HTTP_HOST'] . ' at port 80 with <a href="http://forum.xaknet.ru/">ddos protect</a></i></small>'); } break; default: break; } if ($_COOKIE['ddos'] == $this->indeficator) @unlink($this->dir . ip2long($_SERVER["REMOTE_ADDR"])); } /** * Функция проверяет не является ли клиент поисковым ботом **/ function sbots() { $tmp = array(); foreach($this->searchbots as $bot) { $tmp[] = strpos(gethostbyaddr($_SERVER['REMOTE_ADDR']), $bot) !== false; if($tmp[count($tmp) - 1] == true) { $this->is_bot = true; break; } } return $this->is_bot; } /** * Функция бана **/ private function ban() { if (! system($this->exec_ban)) { $f = fopen($this->dir . 'banned_ips', "a"); fwrite($f, ip2long($_SERVER['REMOTE_ADDR']) . '|'); fclose($f); } die($this->ban_message); } /** * Первый тип защиты **/ function addos1() { if (empty($_COOKIE['ddos']) or !isset($_COOKIE['ddos'])) { $counter = @file($this->dir . ip2long($_SERVER["REMOTE_ADDR"])); setcookie('ddos', $this->indeficator, time() + 3600 * 24 * 7 * 356); // ставим куки на год. if (count($counter) > 10) { if (! $this->debug) $this->ban(); else die("Блокированы."); } if (! $_COOKIE['ddos_log'] == '1') { if (! $_GET['antiddos'] == 1) { setcookie('ddos_log', '1', time() + 3600 * 24 * 7 * 356); //чтоб не перекидывало постоянно рефрешем. if(headers_sent()) die('Header already sended, check it, line '.__LINE__); header("Location: ./?antiddos=1"); } } } elseif ($_COOKIE['ddos'] !== $this->indeficator) { if (! $this->debug) $this->ban(); else die("Блокированы."); } } /** * Второй тип защиты **/ function addos2() { if (empty($_COOKIE['ddos']) or $_COOKIE['ddos'] !== $this->indeficator) { if (empty($_GET['antiddos'])) { if (! $_COOKIE['ddos_log'] == '1') //проверям есть ли запись в куках что был запрос die('<meta http-equiv="refresh" content="0;URL=?antiddos=' . $this->indeficator . '" />'); } elseif ($_GET['antiddos'] == $this->indeficator) { setcookie('ddos', $this->indeficator, time() + 3600 * 24 * 7 * 356); setcookie('ddos_log', '1', time() + 3600 * 24 * 7 * 356); //типо запрос уже был чтоб не перекидывало постоянно рефрешем. } else { if (!$this->debug) $this->ban(); else { echo "May be shall not transform address line?"; die("Блокированы."); } } } } /** * Третий тип защиты **/ function addos3() { if (! isset($_SERVER['PHP_AUTH_USER']) || $_SERVER['PHP_AUTH_USER'] !== $this->ddosuser || $_SERVER['PHP_AUTH_PW'] !== $this->ddospass) { header('WWW-Authenticate: Basic realm="Vvedite parol\': ' . $this->ddospass . ' | Login: ' . $this->ddosuser . '"'); header('HTTP/1.0 401 Unauthorized'); if (! $this->debug) $this->ban(); else die("Блокированы."); die("<h1>401 Unauthorized</h1>"); } } } /* // Exmaple $ad = new antiDdos(false); $ad->dir = 'bots/'; $ad->ddos = 2; $ad->start(); */ ?>
Скрипт Boolean
<?php #(c) Boolean. ##################################################################################### ##################################################################################### ##################################################################################### ##################################################################################### $config['time'] = 2; #Время обращения к скрипту, после которого будет(возможно) выдан бан. $config['countaban'] = 5; #количество возможных нарушений времени обращения, такая возможность введена для более детально точного отделения пользователей от атакующих ботов. $config['directory'] = '_temp'; #временна директория, должна существовать, и иметь права на запись. $config['checkmask'] = 'check'; #маска для проверки, не стоит трогать. $config['banmask'] = 'ban'; #маска для бана, не стоит трогать. #Комманды после нарушения времени и кол-ва обращений. Используйте константу [IP] - IP Бота. $config['commands'][] = 'iptables -A ISPMGR -s [IP] -j DROP'; $config['commands'][] = 'iptables -I INPUT -s [IP] -j DROP'; #Доверенные IP. $config['white']['ip'] = @file('whiteips.txt'); #Доверенные ЮзерАгенты. $config['white']['useragent'][] = 'Google bot'; $config['white']['useragent'][] = 'Yasha bot'; #Сообщение для пользователя. HTML Работает. $config['message'] = file_get_contents("ddosmessage.html"); ##################################################################################### ##################################################################################### ##################################################################################### ##################################################################################### $ip = $_SERVER['REMOTE_ADDR']; $useragent = $_SERVER['HTTP_USER_AGENT']; if ( ! is_dir($config['directory']) ) exit("Temp directory not found."); if ( ! is_writable($config['directory']) ) exit("Temp directory is not writable."); if ( @in_array($ip,$config['white']['ip']) || @in_array($useragent,$config['white']['useragent']) ) $white = true; if ( ! $white ){ if ( file_exists( $config['directory'] . "/" . $config['checkmask'] . $ip ) ){ $time = filemtime($config['directory'] . "/" . $config['checkmask'] . $ip); $f=fopen( $config['directory'] . "/" . $config['checkmask'] . $ip , 'w' ); fclose($f); if ($time >= time() - $config['time']){ if (file_exists($config['directory'] . "/" . $config['banmask'] . $ip)){ $count = file_get_contents($config['directory'] . "/" . $config['banmask'] . $ip); if ($count >= $config['countaban']){ for($i = 0; $i <= count($config['commands']) - 1; $i++) @system(str_replace("[IP]",$ip,$config['commands'][$i])); }else{ $time = filemtime($config['directory'] . "/" . $config['banmask'] . $ip); if ($time >= time() - $config['time']){ $count++; $f=fopen( $config['directory'] . "/" . $config['banmask'] . $ip , 'w' ); fwrite($f,$count); fclose($f); }else{ $f=fopen( $config['directory'] . "/" . $config['banmask'] . $ip , 'w' ); fwrite($f,"1"); fclose($f); } } }else{ $f=fopen( $config['directory'] . "/" . $config['banmask'] . $ip , 'w' ); fwrite($f,"0"); fclose($f); } exit($config['message']); } }else{ $f=fopen( $config['directory'] . "/" . $config['checkmask'] . $ip , 'w'); fclose($f); } } ?>