Предыстория
DDOS-ы это наша реальность и действительность в которой мы живем. В этом смысле читать отчеты от Cloudflare всегда крайне занимательно. С чисто практической же точки зрения все что нужно понимать это тот факт, что объемы DDOS-атак уже давно исчисляются сотнями гигабит на хост. Увы, надеяться на хостера в данном случае можно в крайне ограниченно ибо даже у самого лучшего хостера крайне ограничены возможности по работе с трафиком.
Справочная информация
Для того, чтобы мы далее могли говорить на одном языке немного поговорим о типологии DDOS атак. Сразу оговорюсь, что строгой и выверенной и полной классификации я тут не дам, но постараюсь оставить ссылки для более глубокого ознакомления с предметной областью.
L4 атаки
Суть атаки сводится к эксплуатации особенностей UDP протокола а именно - отсутствие проверки отправителя. По своей сути UDP вообще ничего не проверяет и фактически отправляет ответ на тот IP адрес, который указан в заголовке отправленного пакета. Профит такого подхода заключается в многократном превышении объёма ответа по сравнению с запросом. Сверху на все это накладывает повсеместность использования UDP (DNS, NTP, SNMP, rsyslog) и далеко не все администраторы аккуратно и правильно настраивают сервисы, а иногда и вовсе не настраивают и оставляют настройки по умолчанию. Яркими представителями такого типа атак являются:
- DNS Reflection. В основе лежит отправка множества запросов с поддельными IP-адресами от имени жертвы на DNS-серверы. Подробнее о данной и не только атаке и методах ее митигации рекомендую прочитать в данном whitepaper-е. Сразу оговорюсь, что не со всеми тезисами из данной работы я согласен, однако статистика приведенная там в справедлива до сих пор.
- UDP Flood. Тут все несколько менее интересно и более просто, но от того не менее эффективно. В атаке используются непосредственно боты в ботнете в большом количестве. Каждый из ботов начинает заливать целевой IP вредоносными UDP пакетами и загружает ими канал.
Достигаемый эффект
Забивание канала. Автор лично участвовал в ликвидации 80-гигабитной L4 комбинированной атаки, в которой был и UDP Flood c амплификацией и DNS Reflection. В общем, все и сразу.
Стоимость
Крайне дешево. В принципе, достаточно несколько ботнетов из крайне тупых устройств (от камер до кофеварок), чтобы организовать такую атаку.
L7 атаки
Дорого, но надежно - вот лозунг данной группы атак. В такой атаке вас заливают полноценным TCP трафиком, точно зная, что на вашем конкретном IP и порту поднят какой-то сервис, способный принимать TCP пакеты. Чаще всего заливают 80 и 443 порт. Если совсем грубо, то шлют вполне валидные запросы к серверу в таких количествах, что веб сервер обрабатывая такие запросы нагружает сервер, поднимается LA и сервер просто перестает отвечать.
В частных случаях могут заливать далеко не только 80 и 443 порт. Например 3306 - порт на котором обычно слушает Mysql его также можно заливать неавторизованными запросами на подключение. По умолчанию параметр max_connections
в Mysql равен 151. Иными словами, если ваш сервис (в частности сайт) пытается подключиться к Mysql и сделать запрос к базе, то будучи 152 одновременным коннектом ответа он не получит, а вы не получите ответ на сайте.
Достигаемый эффект
Деградация Web-приложения от банального исчерпания ресурсов сервера до достижения различных максимальных лимитов.
SYN Flood
Немного отдельно от всего этого стоит довольно популярный тип атак - SYN Flood данный тип атак базируется на механизме работы TCP протокола. Лучшая формулировка из всех виденных мной на русском языке такова
Клиент генерирует SYN-пакет, запрашивая новую сессию у сервера. Поскольку TCP сессия открыта (алгоритм “трехэтапного рукопожатия TCP” исполнен), хост будет отслеживать и обрабатывать каждую пользовательскую сессию, пока она не будет закрыта. Во время SYN Flood атакуемый сервер с большой скоростью получает поддельные SYN-запросы, содержащие поддельный IP-адрес источника. SYN-флуд поражает сервер, занимая всю память таблицы соединений (Transmission Control Block (TCB) table), обычно используемую для хранения и обработки входящих пакетов. Это вызывает критическое падение производительности и, как итог, отказ в работе сервера.
Подробнее о данной атаке и принципах защиты от нее можно прочитать в данной статье
Достигаемый эффект
Деградация производительности сетевой подсистемы сервера вплоть до полного отказа в работе.
Стоимость
Сопоставима с UDP Flood, но требует чуть больше навыков от злоумышленника
Как быть и защищаться?
Автор неоднократно нелестно отзывался о SaaS-ах в предыдущих постах, однако тут вынужден признать - единственный способ спать относительно спокойно в части DDOS-атак - работать с SaaS-ами. DDOS-Guard, Qrator, Cloudflare в общем то значения не имеет. Признаемся честно - при цифрах в сотнях гигабит трафика сделать что-то самостоятельно с одной дохлой VPS-кой и без контроля над сетевым оборудованием ничего не получится. Хостинг-провайдеру же дешевле будет на бордере заблокировать трафик к вашей VPS и выплатить вам компенсацию, чем пытаться оборонять вас какими-то хитрыми методами, особенно если речь пойдет о HTTP флуде, забивающем весь канал. Иными словами, единственный наш выход - не подпускать мусорный трафик не только до VPS, но и вовсе до оборудования хостера.
Дальнейшее повествование пойдет на примере Cloudflare, но суть от этого не поменяется.
Шаг №1 регистрация домена
Да - вот так вот внезапно. Рекомендую начать именно с регистрации домена и сразу же при регистрации делегировать NS-ы Cloudflare с тем, чтобы в истории DNS A-записи домена не был зафиксирована реальный IP VPS.
Публичных сервисов, фиксирующих историю DNS-записей доменов много и было бы неплохо, чтобы они не успели зафиксировать ничего кроме IP Cloudflare.
Почему это важно? Любой DDOS - это всегда про работу с IP адресом. Фактически, если даже вы, в какой-то момент отправили домен за Cloudflare, но IP VPS, на котором работает сервис (сайт) остался прежним - злоумышленники будут иметь возможность заливать напрямую IP просто взяв его в истории DNS.
Что делать если домен уже есть и IP уже засветился в истории? - Менять IP на VPS, а старый опустить и вернуть хостеру.
Шаг №2 Whitelist на VPS
Лучший способ борьбы с DDOS - не подпускать к себе DDOS. Иными словами настраиваем на VPS Whitelist на уровне iptables. Благо сами CF нам в этом активно помогают и выставляют список своих подсетей для всех желающих в открытом доступе
Для того, чтобы не быть занудным сразу приложу правила для IPTABLES:
-A INPUT -s your_ip -p tcp -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -j DROP
-A OUTPUT -s your_ip -p tcp -j ACCEPT
-A OUTPUT -o lo -j ACCEPT
-A OUTPUT -j ACCEPT
-A DOCKER-USER -m conntrack --ctstate RELATED,ESTABLISHED -j RETURN
-A DOCKER-USER -s 131.0.72.0/22 -p tcp -m multiport --dports 80,443 -j RETURN
-A DOCKER-USER -s 172.64.0.0/13 -p tcp -m multiport --dports 80,443 -j RETURN
-A DOCKER-USER -s 104.24.0.0/14 -p tcp -m multiport --dports 80,443 -j RETURN
-A DOCKER-USER -s 104.16.0.0/13 -p tcp -m multiport --dports 80,443 -j RETURN
-A DOCKER-USER -s 162.158.0.0/15 -p tcp -m multiport --dports 80,443 -j RETURN
-A DOCKER-USER -s 198.41.128.0/17 -p tcp -m multiport --dports 80,443 -j RETURN
-A DOCKER-USER -s 197.234.240.0/22 -p tcp -m multiport --dports 80,443 -j RETURN
-A DOCKER-USER -s 188.114.96.0/20 -p tcp -m multiport --dports 80,443 -j RETURN
-A DOCKER-USER -s 190.93.240.0/20 -p tcp -m multiport --dports 80,443 -j RETURN
-A DOCKER-USER -s 108.162.192.0/18 -p tcp -m multiport --dports 80,443 -j RETURN
-A DOCKER-USER -s 141.101.64.0/18 -p tcp -m multiport --dports 80,443 -j RETURN
-A DOCKER-USER -s 103.31.4.0/22 -p tcp -m multiport --dports 80,443 -j RETURN
-A DOCKER-USER -s 103.22.200.0/22 -p tcp -m multiport --dports 80,443 -j RETURN
-A DOCKER-USER -s 103.21.244.0/22 -p tcp -m multiport --dports 80,443 -j RETURN
-A DOCKER-USER -s 173.245.48.0/20 -p tcp -m multiport --dports 80,443 -j RETURN
-A DOCKER-USER -j DROP
-A DOCKER-USER -j RETURN
Особо внимательный читатель тут может заметить, что в данном случае я применяю правила с подсетями Cloudflare в цепочке DOCKER-USER и это справедливо для меня, т.к. веб сервер в моем случае работает в Docker-контейнере с сетью в brige. Однако если ваш сайт поднят прямо на хосте никто не мешает применить эти правила к цепочке INPUT.
И сразу приложу готовый playbook для ansible, который я написал, чтобы не раскатывать нужные правила в iptables руками
- hosts: myblog
gather_facts: no
become: yes
tasks:
- name: Allow for my ip
ansible.builtin.iptables:
chain: "{{ item[0] }}"
protocol: tcp
source: "{{ item[1] }}"
jump: ACCEPT
with_nested:
- [ 'INPUT', 'OUTPUT' ]
- [ your_ips ] # тут нужно ввести те IP, кроме cloudflare, с которых можно заходить на вашу VPS для менеджмента
- name: Allow established sessions to receive traffic
ansible.builtin.iptables:
chain: INPUT
ctstate: ESTABLISHED,RELATED
jump: ACCEPT
- name: Accept INPUT on localhost
ansible.builtin.iptables:
chain: INPUT
in_interface: lo
jump: ACCEPT
- name: Accept OUPUT on localhost
ansible.builtin.iptables:
chain: OUTPUT
out_interface: lo
jump: ACCEPT
- name: DROP for docker
ansible.builtin.iptables:
action: insert
chain: "DOCKER-USER"
jump: DROP
- name: Allow on 80 and 443 ports for cloudflare networks
ansible.builtin.iptables:
action: insert
chain: "{{ item[0] }}"
protocol: tcp
source: "{{ item[1] }}"
destination_ports:
- "80"
- "443"
jump: RETURN
with_nested:
- ['DOCKER-USER']
- [173.245.48.0/20, 103.21.244.0/22, 103.22.200.0/22, 103.31.4.0/22, 141.101.64.0/18, 108.162.192.0/18, 190.93.240.0/20, 188.114.96.0/20, 197.234.240.0/22, 198.41.128.0/17, 162.158.0.0/15, 104.16.0.0/13, 104.24.0.0/14, 172.64.0.0/13, 131.0.72.0/22]
- name: Allow established sessions for docker
ansible.builtin.iptables:
action: insert
chain: DOCKER-USER
ctstate: ESTABLISHED,RELATED
jump: RETURN
- name: DROP other
ansible.builtin.iptables:
chain: "{{ item }}"
jump: DROP
with_items:
- INPUT
- FORWARD
- name: ACCEPT OUTPUT
ansible.builtin.iptables:
chain: OUTPUT
jump: ACCEPT
- name: Save Rules
shell:
cmd: iptables-save > /etc/iptables/rules.v4
Даже если вы никогда не писали никаких плейбуков в Ansible я думаю все довольно таки очевидно и понятно.
Шаг №3 - добавляем пару правил в WAF на уровне Cloudflare
На самом деле играться с правилами файервола в Cloudflare можно почти бесконечно, но самые основные следующие:
Whitelist портов
not (cf.edge.server_port in {80 443})
Мы ведь не хотим, чтобы пакеты не к 80 или 443 в принципе летели к нашей VPS?
Ограничения HTTP методов
(http.request.method ne "GET") and (http.request.method ne "POST") and (http.request.method ne "HEAD") and (http.request.method ne "OPTIONS")
Мой вам совет - не пренебрегайте этим правилом. Заливать невалидными HTTP запросами с методом в заголовке T
и ST
некоторое время назад было излюбленным приемом атакующих, да и до сих пор таковым остается. Суть приема в том, что злоумышленнику вовсе не обязательно получить ответ от сервера, а вот веб сервер вполне себе будет продолжать обрабатывать и такие запросы недоумевая что за странный метод такой пытается использовать клиент. При этом еще и экономится пару байтиков при запросе.
Что в сухом остатке?
- Наша VPS дропает любые пакеты кроме тех, которые идут от разрешенных IP на разрешенные порты.
- Потенциальные злоумышленники знают только IP Cloudflare
- Весь трафик к сайту проксируется через серверы Cloudflare и с большой долей вероятности любой UDP/HTTP/SYN и прочие флуды будут отбиты серверами Cloudflare
- На файерволе Cloudflare мы также железной рукой порезали все лишнее и можем порезать еще, благо Cloudflare позволяет бесплатно конструировать цепочки правил количеством до 5 штук, причем в каждом правиле можно использовать довольно заковыристые логические конструкции.
Что еще можно сделать?
Например настроить интеграцию fail2ban и API cloudflare, настроить request-limit и request-rate на Nginx и еще ряд интересных мелочей, о которых мы поговорим в следующих статьях, посвященных непосредственно настройке веб стека.