Защита от DDoS на уровне веб-сервера
Статистика DDoS-атак показывает неизменный рост и смещение вектора с сетевого уровня на уровень приложений.
Если у Вас есть небольшой сайт на сервере с минимальными характеристиками, то положить его можно любым вполне легальным средством стресс-тестирования. (Не рекомендую этого никому делать т.к. IP-адрес легко вычисляется и экспериментатор может влететь на возмещение ущерба.) Поэтому сайт без защиты от DDoS очень скоро будет выглядеть так же дико, как компьютер с Windows-98 без анивирусника. Первое, что можно и нужно сделать для защиты сайта — настроить брандмауэр iptables. Я использую почти без изменений настройки iptables из статьи на сайте одного из поставщиков защиты от DDoS-атак. Единственное что я поменял — увеличил число допустимых соединений в правилах #8 и #10.
Прежде чем запускать на выполнение скрипт, меняющий параметры iptables, нужно убедиться, что есть альтернативная возможность сбросить эти параметры в начальное состояние. Т.к. если правила заданы неверно, к серверу не сможет подключится никто, в том числе и администратор.
Брандмауэр iptables контролирует атаку на сетевом уровне. Следующее что необходимо настроить — это веб-сервер. В качестве веб-сервера, который открыт для доступа из интернет будем рассматривать nginx. В файле nginx.conf нужно увеличить лимиты на колчество файлов и открытых коннектов (пример взят из Википедии):
Далее настраиваем сервер по умолчанию, который будет запрещать доступ для тех устройств (например IoT), который будут обращаться по IP-адресу а не по доменному имени:
Так же в nginx можно настроить некоторые лимиты на количество обращений, но такая настройка будет не очень гибкой и совсем не избирательной. Наша цель сделать такую защиту на уровне веб-сервера, чтобы погасить запросы злоумышленников, но пропускать на сервер запросы добропорядочных пользователей.
Чтобы не пересказывать уже имеющийся на Хабре материал, предлагаю ознакомится с отличной статьей, а так же с модулем автора указаной статьи kyprizel/testcookie-nginx-module. То, что позволяет сделать этот модуль уже хорошо. Но если Вам понадобится модернизировать его — то сделать это будет непросто.
На сегодняшний день очень многие поставщики услуг защиты от DDoS используют сервер openresty (связка nginx + Lua от Taobao). Скорость выполнения хорошего кода на Lua немного уступает хорошему коду на С. Но разрабатывать на Lua быстрее и проще, и к тому же скрипты можно менять без перекомпиляции сервера. При следуюшем рестарте они будут прочитаны, скомпилированы LuaJIT, и это все что требуется.
Подробная инструкция как уcтановить optnresty. После установки продолжаем настраивать nginx. В разделе http определяем нужные параметры для работы скритов Lua:
Строка lua_shared_dict создает новый словарь (ключ-значение). Этот словарь будет единым для всех запросов, поэтому в нем удобно хранить белые и черные списки. Это словарь, кроме параметров ключ-значение, может иметь параметр time-to-live, который идеально подходит для хранения счетчиков, если нужно ограничить количество запросов в промежуток времени.
Строка lua_package_path задает пути для поиска модулей Lua, в котрый нужно включить каталог со скриптами. Две подряд точки с запятой в конце строки означают, что этот путь добавляется к текущему значению пути, а не полностью заменяет его.
Строка init_by_lua задает код, который будет выполнен один раз при старте сервера (а не при каждом новом запросе). В ней задается белый список IP-адресов. Второй праметр функции add — true — это просто значние которое потом используется в операторе if. Третий параметр time-to-live отсутсвует, поэтому значение будет храниться без ограничения по времени.
Строка access_by_lua_file задает путь к скрипту, который будет выполняться при каждом запросе к серверу (не только при старте сервера). В нем, собственно, и находится вся логика защиты.
Рассмотрим некоторые из проверок, которые можно сделать при помощи скрипта на Lua:
Язык Lua во многом похож (даже слишком) на JavaScript, поэтому код на Lua интуитивно понятен всем, кто пишет на JavaScript.
Глобальная переменная ngx служит для связи с контекстом сервера nginx. Оператор return вне тела функции означает возврат из модуля. В данном примере, если IP-адрес в белом списке, то работа скрипта оканчивается, и продолжается обычная обработка запроса nginx.
Далее распознается атака, основанная на особенностей реализации CMS WordPress. Если атака выявлена то работа оканчивается специальным статусом 444 (характерен только для nginx): ngx.exit(444) .
И, наконец, мы даем «зеленую дорогу» поисковым ботам. Тут приходится использовать счетчик, т.к. под поискового бота часто подделываются злоумышленники — поэтому считаем количество обращений. banlist:set(search_bot, 1, 10) инициализирует счетчик, который обнулится через 10 секунд после создания. banlist:incr(search_bot, 1) прибавляет к текущему значению счетчика единицу.
Дальнейшее распознавание ботов и злоумышленников может вестись по разным направлениям. Как было предложено в статье такое распознавание основано на проверках, поддерживает ли клиент редиректы, установку cookie и выполнения кода JavaScript. Ну или все, что можно еще придумать.
Как правило, такой веб-сервер используют в качестве прокси, а защищаемый веб-сервер размещают на другом IP-адресе.