Защита от DDOS-атак и оптимизация ядра для серверов с высокой нагрузкой

Появилась задача с настройкой защиты от DDOS-атак и оптимизацией ядра серверов с высокой нагрузкой. Методом тестирований и экспериментов, были выбраны оптимальные значения параметров. В данной статье поделюсь своим опытом.

Целочисленное значение в файле tcp_max_syn_backlog определяет максимальное число запоминаемых запросов на соединение, для которых не было получено подтверждения от подключающегося клиента. Если на сервере возникают перегрузки, можно попытаться увеличить это значение.

sudo sysctl -w net.ipv4.tcp_max_syn_backlog=16777214

Не принимать и не отправлять ICMP-пакеты перенаправления. ICMP-перенаправления могут быть использованы злоумышленником для изменения таблиц маршрутизации. Целесообразно выставить в «0». Единица имеет смысл только для хостов, использующихся в качестве маршрутизаторов.

sudo sysctl -w net.ipv4.conf.all.accept_redirects=0
sudo sysctl -w net.ipv4.conf.all.secure_redirects=0
sudo sysctl -w net.ipv4.conf.all.send_redirects=0

Целочисленное значение параметра tcp_max_orphans определяет максимальное число допустимых в системе сокетов TCP, не связанных каким-либо идентификатором пользовательского файла (user file handle). При достижении порогового значения “осиротевшие” (orphan) соединения незамедлительно сбрасываются с выдачей предупреждения. Этот порог помогает предотвращать только простые атаки DoS. Не следует уменьшать пороговое значение (скорее увеличить его в соответствии с требованиями системы – например, после добавления памяти. Каждое orphan-соединение поглощает около 64 Кбайт несбрасываемой на диск (unswappable) памяти.

sudo sysctl -w net.ipv4.tcp_max_orphans=65536

Параметр tcp_fin_timeout определяет время сохранения сокета в состоянии FIN-WAIT-2 после его закрытия локальной стороной. Партнер может не закрыть это соединение никогда, поэтому следует закрыть его по своей инициативе по истечении тайм-аута. По умолчанию тайм-аут составляет 60 секунд. В ядрах серии 2.2 обычно использовалось значение 180 секунд и вы можете сохранить это значение, но не следует забывать, что на загруженных WEB-серверах вы рискуете израсходовать много памяти на сохранение полуразорванных мертвых соединений. Сокеты в состоянии FIN-WAIT-2 менее опасны, нежели FIN-WAIT-1, поскольку поглощают не более 1,5 Кбайт памяти, но они могут существовать дольше.

sudo sysctl -w net.ipv4.tcp_fin_timeout=30

tcp_keepalive_time Переменная определяет как часто следует проверять соединение, если оно давно не используется. Значение переменной имеет смысл только для тех сокетов, которые были созданы с флагом SO_KEEPALIVE. Целочисленная переменная tcp_keepalive_intvl определяет интервал передачи проб. Произведение tcp_keepalive_probes * tcp_keepalive_intvl определяет время, по истечении которого соединение будет разорвано при отсутствии откликов. По умолчанию установлен интервал 75 секунд, т.е., время разрыва соединения при отсутствии откликов составит приблизительно 11 минут.

sudo sysctl -w net.ipv4.tcp_keepalive_time=60
sudo sysctl -w net.ipv4.tcp_keepalive_intvl=15
sudo sysctl -w net.ipv4.tcp_keepalive_probes=5

Целочисленное значение (1 байт) tcp_synack_retries определяет число попыток повтора передачи пакетов SYNACK для пассивных соединений TCP. Число попыток не должно превышать 255. Значение 5 соответствует приблизительно 180 секундам на выполнение попыток организации соединения.

sudo sysctl -w net.ipv4.tcp_synack_retries=1

Согласно рекомендациям разработчиков ядра, этот режим лучше отключить.

sudo sysctl -w net.ipv4.tcp_syncookies=0

Целочисленной значение tcp_orphan_retries определяет число неудачных попыток, после которого уничтожается соединение TCP, закрытое на локальной стороне. По умолчанию используется значение 7, соответствующее приблизительно периоду от 50 секунд до 16минут в зависимости от RTO. На сильно загруженных WEB-серверах имеет смысл уменьшить значение этого параметра, поскольку закрытые соединения могут поглощать достаточно много ресурсов.

sudo sysctl -w net.ipv4.tcp_orphan_retries=3

Максимальное количество соединений для работы механизма connection tracking (используется, например, iptables). При слишком маленьких значениях ядро начинает отвергать входящие подключения с соответствующей записью в системном логе.

sudo sysctl -w net.ipv4.netfilter.ip_conntrack_max=1048576

Увеличиваем диапазон локальных портов, доступных для установки исходящих подключений

sudo sysctl -w net.ipv4.ip_local_port_range=1024 61000

Защищаемся от TIME_WAIT атак.

sudo sysctl -w net.ipv4.tcp_rfc1337=1

Активируем защиту от IP-спуфинга.

sudo sysctl -w net.ipv4.conf.all.rp_filter=1
sudo sysctl -w net.ipv4.conf.lo.rp_filter=1
sudo sysctl -w net.ipv4.conf.eth0.rp_filter=1
sudo sysctl -w net.ipv4.conf.default.rp_filter=1

Не отвечаем на ICMP ECHO запросы, переданные широковещательными пакетами

sudo sysctl -w net.ipv4.icmp_echo_ignore_all=1

По сути, мы выполнили эти команды и можем проверить работу ядра.

net.ipv4.tcp_max_syn_backlog=16777214
net.ipv4.conf.all.accept_redirects=0
net.ipv4.conf.all.secure_redirects=0
net.ipv4.conf.all.send_redirects=0
net.ipv4.tcp_max_orphans=65536
net.ipv4.tcp_fin_timeout=30
net.ipv4.tcp_keepalive_time=60
net.ipv4.tcp_keepalive_intvl=15
net.ipv4.tcp_synack_retries=1
net.ipv4.tcp_syncookies=0
net.ipv4.tcp_orphan_retries=3
net.ipv4.netfilter.ip_conntrack_max=1048576
net.ipv4.ip_local_port_range=1024 61000
net.ipv4.tcp_rfc1337=1
net.ipv4.conf.all.rp_filter=1
net.ipv4.conf.lo.rp_filter=1
net.ipv4.conf.eth0.rp_filter=1
net.ipv4.conf.default.rp_filter=1
net.ipv4.icmp_echo_ignore_all=1

Если все все получилось наверняка, выполняем в консоли и вносим изменения чтобы закрепить настройки после перезагрузки сервера.

echo «net.ipv4.tcp_max_syn_backlog=16777214» | sudo tee -a /etc/sysctl.conf
echo «net.ipv4.conf.all.accept_redirects=0» | sudo tee -a /etc/sysctl.conf
echo «net.ipv4.conf.all.secure_redirects=0» | sudo tee -a /etc/sysctl.conf
echo «net.ipv4.conf.all.send_redirects=0» | sudo tee -a /etc/sysctl.conf
echo «net.ipv4.tcp_max_orphans=65536» | sudo tee -a /etc/sysctl.conf
echo «net.ipv4.tcp_fin_timeout=30» | sudo tee -a /etc/sysctl.conf
echo «net.ipv4.tcp_keepalive_time=60» | sudo tee -a /etc/sysctl.conf
echo «net.ipv4.tcp_keepalive_intvl=15» | sudo tee -a /etc/sysctl.conf
echo «net.ipv4.tcp_keepalive_probes=5» | sudo tee -a /etc/sysctl.conf
echo «net.ipv4.tcp_synack_retries=1» | sudo tee -a /etc/sysctl.conf
echo «net.ipv4.tcp_syncookies=0» | sudo tee -a /etc/sysctl.conf
echo «net.ipv4.tcp_orphan_retries=3» | sudo tee -a /etc/sysctl.conf
echo «net.ipv4.netfilter.ip_conntrack_max=1048576» | sudo tee -a /etc/sysctl.conf
echo «net.ipv4.ip_local_port_range=1024 61000» | sudo tee -a /etc/sysctl.conf
echo «net.ipv4.tcp_rfc1337=1» | sudo tee -a /etc/sysctl.conf
echo «net.ipv4.conf.all.rp_filter=1» | sudo tee -a /etc/sysctl.conf
echo «net.ipv4.conf.lo.rp_filter=1» | sudo tee -a /etc/sysctl.conf
echo «net.ipv4.conf.eth0.rp_filter=1» | sudo tee -a /etc/sysctl.conf
echo «net.ipv4.conf.default.rp_filter=1» | sudo tee -a /etc/sysctl.conf
echo «net.ipv4.icmp_echo_ignore_all=1» | sudo tee -a /etc/sysctl.conf

Проверка текущих статусов:

sudo sysctl net.ipv4.tcp_max_syn_backlog
sudo sysctl net.ipv4.conf.all.accept_redirects
sudo sysctl net.ipv4.conf.all.secure_redirects
sudo sysctl net.ipv4.conf.all.send_redirects
sudo sysctl net.ipv4.tcp_max_orphans
sudo sysctl net.ipv4.tcp_fin_timeout
sudo sysctl net.ipv4.tcp_keepalive_time
sudo sysctl net.ipv4.tcp_keepalive_intvl
sudo sysctl net.ipv4.tcp_keepalive_probes
sudo sysctl net.ipv4.tcp_synack_retries
sudo sysctl net.ipv4.tcp_syncookies
sudo sysctl net.ipv4.tcp_orphan_retries
sudo sysctl net.ipv4.netfilter.ip_conntrack_max
sudo sysctl net.ipv4.ip_local_port_range
sudo sysctl net.ipv4.tcp_rfc1337
sudo sysctl net.ipv4.conf.all.rp_filter
sudo sysctl net.ipv4.conf.lo.rp_filter
sudo sysctl net.ipv4.conf.eth0.rp_filter
sudo sysctl net.ipv4.conf.default.rp_filter
sudo sysctl net.ipv4.icmp_echo_ignore_all