DDOS: защита от атак
Преамбула
В первую очередь стоит сказать, что DDOS атаки бывают разных типов. Самое простое - чрезмерная нагрузка на веб-сервер, при которой он просто не в состоянии обрабатывать запросы с той скоростью, с которой запрашиваются данные, на ней я и хочу заострить внимание.
Достаточно совсем небольшое количество ботов, посылающих запросы даже не очень быстро. Как защититься? В интернете полно статей про установку фаерволов (конфигурирование iptables) направленных на ограничение количества подключений и т.п. Но что если боты ведут себя как люди? К примеру 1000 ботов запрашивающих по 1 странице в секунду создадут очень большую нагрузку, но без специального оборудования, например такиого как CISCO GUARD врядли удастся отсетить "плохой" трафик, и далеко не каждому по карману железка за 20к долларов. Хотя конечно стоит сказать, что преимуществ у нее очень много и спасет она не только от распределенной атаки на ресурсы веб-сервера, а так же от флуда и т.п. видов атак.
Итак, что же делать, когда стало совсем плохо? Первое, что приходит в голову - кэширование данных. Но возможно будет сложным закэшировать какое-то веб приложение в котором каждый пользователь видит страницу "по-своему", да и так или иначе даже отдача большого количества статики будет забивать канал сервера.
В поисках простого и действенного метода я наткнулся на трейд, где предлагалось проверять куки в начале скрипта и в зависимости от того, установлены они или нет, отдавать страницу пользователю. Если куков нет - редиректим на статическую HTML страницу, которая яваскриптом устанавливает куку пользователю и сразу редиректим его обратно, если же куки есть - то значит пользователь прошел верификацию и ему можно отдать контент. Но некоторые могут завозмущаться - раз мы уже выполняем скрипт, то мы тратим определенное колчиество ресурсов (хоть и меньшее, чем генерация полноценной страницы, но все же). Именно по этому я и сразу не оценил этот способ. Но меня не отпускала мысль, как сделать все эти проверки не затрагивая PHP (или другой интепретатор)? И тут пришла мысль ипользовать RewriteMod.
Суть метода заключается в том же, но заметно снижаем нагрузку: проверяем куки с помощью RewriteMod, с помощью него же редиректим, если нужно.
Итак, к делу
Думаю смысл системы уже понятен, осталось все это грамотно реализовать.
Первое, что нам надо сделать, это проверить наличие куки, и если ее нет, то отдать пользователю HTML страницу с JS, который эту куку установит.
- RewriteEngine On
- RewriteCond %{http_cookie} !bb_mode=1825743668
- RewriteRule .* redirect.html [L]
Здесь мы смотрим, установлена ли кука bb_mode, если нет, то отдаем пользователю страничку redirect.html - отдача статики размером в 800 байт - даже для апачи дело "раз плюнуть".
Обратите внимание! Мы не просто редиректим пользователя, а подменяем страницу, это избавит от лишнего запроса к серверу и сделает процесс не заметным для "нормального" пользователя.
Если пользователь попал на эту страницу, надо поставить ему куку:
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
- "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE">
- <META HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE">
- <META HTTP-EQUIV="REFRESH" CONTENT="0;">
- <title></title>
- </head>
- <body>
- <script type="text/javascript">
- document.cookie = 'bb_mode=1825743668; path=/';
- </script>
- </body>
- </html>
Прописываем в мета-тегах заголовки, указывающие браузеру о том, что кэшировать это не надо, иначе он просто зациклится на ней. Тут же делаем рефреш страницы после загрузки. Ну и собственно устанавливаем куку.
Вот и все.
Пользователь приходит на сайт, система проверяет, есть ли у него необходимая кука, если нету, ставит и обновляет страницу, после чего кука у него уже будет и правило подмены странички не сработает и пользователь получит реальную страницу. Боты же не смогут выполнить скрипт и при запросе любой страницы будут полчать эту HTML-ку.
Немного усложним жизнь ботам
Возможно, что неугомонный ботовод на этом не сдастся и добавит данную куку ботам. На этот случай будем менять значение куки каждые N-минут по крону:
- $cookie = mt_rand();
- $s = file_get_contents('.htaccess');
- $s = preg_replace('#(bb_mode\=)\d+#', 'bb_mode='.$cookie, $s);
- file_put_contents('.htaccess', $s);
- $p = file_get_contents('redirect.html');
- $p = preg_replace('#(bb_mode\=)\d+#', 'bb_mode='.$cookie, $p);
- file_put_contents('redirect.html', $p);
Не забываем поставить на файлы .htaccess и redirect.html необходимые права доступа.
А как же поисковые системы?
Скорее всего поисковая система тоже не сможет получить доступ к настоящей странице. Хотя многие говорят о том, что они уже умеют выполнять JS код. Но если хотите перестраховаться, то просто немножко расширим правило:
- RewriteCond %{http_cookie} !bb_mode=1825743668
- #Goodle
- RewriteCond %{REMOTE_ADDR} !66.249.0.0/16
- #Rambler
- RewriteCond %{REMOTE_ADDR} !81.19.64.0/24
- RewriteCond %{REMOTE_ADDR} !81.19.65.0/24
- RewriteCond %{REMOTE_ADDR} !81.19.66.0/24
- #Yandex
- RewriteCond %{REMOTE_ADDR} !77.88.24.0/24
- RewriteCond %{REMOTE_ADDR} !77.88.25.0/24
- RewriteCond %{REMOTE_ADDR} !77.88.26.0/24
- RewriteCond %{REMOTE_ADDR} !77.88.27.0/24
- RewriteRule .* redirect.html [L]
Теперь для данных блоков адресов проблем с доступам к настоящему контенту не будет.
Послесловие
Таким способом мне удалось вывести сервер из глубокой комы. После проделанных действий Load Average с 200 упал до 0.2
Боты кормятся своими 700 байтами и даже не забивают канал.