===== Настройка веб-сервера на базе стека LEMP в Ubuntu Server 14.04 LTS. Часть 3. Усиление безопасности системы. =====
==== Настройка параметров sysctl ====
Добавляем в **/etc/sysctl.conf** некоторые параметры, которые помогут усилить стойкость системы перед всевозможными флуд-атаками:
#
# Включаем фильтрацию входящих пакетов,
# которые были отправлены одним интерфейсом, а приняты другим.
#
net.ipv4.conf.default.rp_filter = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.lo.rp_filter = 1
net.ipv4.conf.eth0.rp_filter = 1
# Запрещаем маршрутизацию от источника.
# Маршрутизация от источника (source routing) позволяет отправителю
# определить путь, по которому пакет должен пройти по сети Internet, чтобы
# достигнуть пункта назначения. Это очень удобно для изучения и отладки
# работы сети, но нарушитель получает возможность подмены адресов
# компьютеров локальной сети. 0 означает, что маршрутизация отключена, 1 - наоборот.
#
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.lo.accept_source_route = 0
net.ipv4.conf.eth0.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
# Выключаем приём и отправку ICMP-пакетов перенаправления.
# Включение параметров имеет смысл только на муршрутизирующем сервере, а у нас задачи другие.
#
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.all.send_redirects = 0
# Увеличиваем порог осиротевших (orphan) соединений.
# При возникновении проблем, связанных с этим ограничением в
# системный журнал будет записано сообщение, подобное этому: TCP: too many
# of orphaned sockets Это может служить поводом к тому, чтобы пересмотреть
# значения переменных tcp_fin_timeout или tcp_orphans_retries.
# Значение по умолчанию 16384
#
net.ipv4.tcp_max_orphans = 65536
# Использовать более частую проверку TCP-соединений.
# Если на другой стороне - реальная машина, она сразу ответит.
# Значение переменной имеет смысл только для тех сокетов,
# которые были созданы с флагом SO_KEEPALIVE
# Значение по умолчанию - 7200 секунд / 2 часа.
#
net.ipv4.tcp_keepalive_time = 1800
# Уменьшаем интервал проверки жизнеспособности TCP-соединения.
# Это значение учитывается при подсчете времени,
# которое должно пройти перед тем как соединение будет разорвано.
# Значения по-умолчанию:
# net.ipv4.tcp_keepalive_intvl = 75 секунд.
# net.ipv4.tcp_keepalive_probes = 9
# Значения этих переменных могут использоваться для определения времени,
# через которое соединение будет разорвано.
# Со значениями по-умолчанию (9 попыток с интервалом 75 секунд) это займет примерно 11 минут.
# Попытки определения жизнеспособности, в свою очередь, начнутся через интервал времени
# определённый в tcp_keepalive_time после того,
# как через данное соединение проследовал последний пакет.
#
net.ipv4.tcp_keepalive_intvl = 15
net.ipv4.tcp_keepalive_probes = 5
# Отключаем ответы на ICMP-запросы, чтобы защититься от ICMP-флуда
# Как альтернативный вариант закрыть ICMP на iptables:
# iptables -A INPUT -p icmp -j DROP --icmp-type 8
#
net.ipv4.icmp_echo_ignore_all = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
# Включаем передачу syncookies вызывающему хосту в случае переполнения
# очереди SYN-пакетов для заданного TCP-соединения.
#
net.ipv4.tcp_syncookies=1
# Увеличиваем очередь «полуоткрытых» TCP-соединений
# (максимальное число запоминаемых запросов на соединение,
# для которых не было получено подтверждения от подключающегося клиента)
# Эта опция работает только тогда, когда включена переменная tcp_syncookies.
# Если сервер испытывает серьезные нагрузки, то можно попробовать увеличить этот параметр.
# Значение по-умолчанию равно 128.
# Если сервер имеет больше 128MB ОЗУ, то значение можно установить в 1024 и более.
#
net.ipv4.tcp_max_syn_backlog = 1024
# Уменьшаем количество попыток передачи SYN,ACK-пакета в ответ на SYN-запрос.
# т.е. максимальное число попыток установить пассивное TCP-соединение,
# инициированное другим хостом.
# Значение по-умолчанию 5.
#
net.ipv4.tcp_synack_retries = 2
# Уменьшаем время пребывания сокета в состоянии FIN-WAIT-2 (целое число в секундах)
# Используется в тех случаях, когда другая сторона
# по тем или иным причинам не закрыла соединение со своей стороны.
# Каждый сокет занимает в памяти порядка 1.5 Кб,
# что может привести к значительным утечкам памяти в некоторых случаях.
# Значение по умолчанию - 60 секунд.
#
net.ipv4.tcp_fin_timeout = 10
# Увеличиваем длинну очереди пакетов на обработку в случае,
# если интерфейс получает пакеты быстрей, чем ядро сможет обработать их.
# Значение по умолчанию 1000.
#
net.core.netdev_max_backlog = 10000
# Увеличиваем максимальное число всех открытых сокетов которые ждут соединения.
# Значение по умолчанию 128.
#
net.core.somaxconn = 10240
# Отключаем сохранение результатов измерений TCP-соединения в кеше при его закрытии.
# Может положительно повлиять на производительность
#
net.ipv4.tcp_no_metrics_save = 1
# Включаем реализацию защиты от TIME_WAIT атак.
#
net.ipv4.tcp_rfc1337 = 1
# Запрещаем переадресацию пакетов (имеет смысл на маршрутизаторе)
#
net.ipv4.ip_forward = 0
Сохраним файл и применим его изменения в системе:
sudo sysctl -p
\\
\\
==== Настройка iptables ====
\\
=== Защита от атак UDP flood ===
Атаки UDP flood основаны на массированной посылке UDP-пакетов на порты различных UDP-сервисов.
Защиту можно реализовать путём изоляции UDP-сервисов от Интернет (если это возможно) или путём установки лимита количества соединений в единицу времени от каждого отдельно взятого внешнего IP.
Например, если наружу выставлен DNS-сервис (порт UDP 53), можно попробовать настроить такое ограничение с помощью iptables следующим правилом:
sudo iptables -I INPUT -p udp --dport 53 -j DROP -m iplimit --iplimit-above 1
\\
=== Ограничение TCP подключений ===
Атаки HTTP flood основаны на массовой посылке HTTP-сообщений GET на TCP-порт веб-сервера с целью создания критической нагрузки на сервер.
При этом посылаться запросы могут как к корню веб-сервера, так и к всевозможным ресурсоёмким скриптам.
Помимо общей нагрузки на систему HTTP flood может привести к аномальному росту логов веб-сервера.
Далее можно поставить ограничение по количеству одновременных соединений
# Лимит 1000/сек пакетов всего
sudo iptables -N TCP-FLOOD
sudo iptables -I INPUT -p tcp -m multiport --dports 80,443,758 -i eth0 -j TCP-FLOOD \
-m comment --comment "Limit TCP connections"
sudo iptables -A TCP-FLOOD -m limit --limit 1000/sec -j RETURN \
-m comment --comment "Limit TCP connections"
sudo iptables -A TCP-FLOOD -j DROP -m comment --comment "Limit TCP connections"
\\
=== Защита от атак SYN flood ===
Ограничиваем максимальное число «полуоткрытых» соединений с одного IP к конкретному порту (не больше 50 соединений на каждый IP):
sudo iptables -A INPUT -p tcp --syn -m multiport --dports 80,443,522 \
-m connlimit --connlimit-above 50 -j REJECT \
-m comment --comment "Prevent SYN flood"
Отбрасываем неправильно сформированные пакеты:
sudo iptables -A INPUT -m conntrack --ctstate INVALID -j DROP \
-m comment --comment "Prevent invalid packets"
Не забываем сохранить правила iptables:
sudo sh -c "iptables-save > /etc/iptables.conf"
\\
=== Защита от атак SYN flood (скрипт с netstat и ipset) ===
Предварительно проверить ситуацию на наличие присутствия SYN_RECV соединений можно посчитав их количество:
sudo netstat -n --tcp | grep SYN_RECV | wc -l
Другой пример. Просмотр количества полуоткрытых соединений в разрезе IP
netstat -nap | grep SYN_RECV | awk {'print $5'} | awk -F: {'print $1'} | sort -rn | uniq -c | sort -rn
Рассмотрим пример скрипта для зашиты от атак TCP SYN flood с использованием связки iptables + ipset + netstat.
ipset - это расширение для iptables, которое позволяет работать с большими массивами данных, например IP-адресов,
обработка которых может быть вызвана из правил iptables
Чтобы установить расширение выполним:
sudo apt-get install ipset
После того как пакет установлен, создаём собственную цепочку **ipset**, например с названием "**DOS-SRC**"
sudo ipset -N DOS-SRC iphash
Добавляем в iptables в цепочке **INPUT** правило блокирования всех пакетов для всех хостов, которые обнаруживаются в цепочке ipset "DOS-SRC":
sudo iptables -I INPUT 1 -m set --match-set DOS-SRC src -j DROP \
-m comment --comment "Prevent SYN_RECV DOS"
Сохраняем правила iptables:
sudo sh -c "iptables-save > /etc/iptables.conf"
Создадим каталоги для хранения вспомогательных файлов...
Каталог для хранения скрипта обновления цепочек ipset (**ipset-DOS-SRC-refresh.sh**):
sudo mkdir /etc/ipset/
sudo chmod 755 /etc/ipset/
Каталог для сохранения файла цепочек ipset (**ipset.conf**):
sudo mkdir /var/local/ipset/
sudo chmod 755 /var/local/ipset/
Создадим скрипт, с помощью которого будет обновляться созданная нами ранее цепочка ipset "**DOS-SRC**":
sudo touch /etc/ipset/ipset-DOS-SRC-refresh.sh
sudo chmod +x /etc/ipset/ipset-DOS-SRC-refresh.sh
sudo nano /etc/ipset/ipset-DOS-SRC-refresh.sh
Наполним скрипт содержимым:
#!/bin/bash
IFCONFIG=/sbin/ifconfig
GREP=/bin/grep
AWK=/usr/bin/awk
CUT=/usr/bin/cut
NETSTAT=/bin/netstat
IPSET=/sbin/ipset
IPTABLES=/sbin/iptables
SORT=/usr/bin/sort
UNIQ=/usr/bin/uniq
srvIP=`$IFCONFIG eth0 | $GREP 'inet addr' | $AWK '{print $2}' | $CUT -f2 -d ":"`
for i in `$NETSTAT -ntu | $GREP SYN_RECV | $AWK '{print $5}' | $CUT -f1 -d ":" | $SORT | $UNIQ | $GREP -v ${srvIP}`
do
$IPSET -A DOS-SRC $i
done
$IPSET -S > /var/local/ipset/ipset.conf
Скрипт анализирует вывод команды **netstat**, выбирает соединения в состоянии **SYN_RECV** (признак SYN флуда) и добавляет эти IP в цепочку "**DOS-SRC**" утилиты ipset, а члены этой цепочки в свою очередь в режиме реального времени
блокируется в **iptables** в цепочке **INPUT**.
Запустим скрипт для проверки того, что при его запуске из cron не возникнет проблем:
sudo sh -c "/sbin/ipset -S > /var/local/ipset/ipset.conf"
В файл **/etc/rc.local** добавляем строчку восстановления сохранённого списка заблокированных адресов после перезагрузки системы:
sudo nano /etc/rc.local
Впишем команду загрузки ранее сохранённых правил ipset из файла ipset.conf (строку добавлять нужно до команды загрузки основных правил iptables):
#
# Load ipset chains and rules
cat /var/local/ipset/ipset.conf | /sbin/ipset -R
#
# Load iptables rules from this file
iptables-restore < /etc/iptables.conf
#
exit 0
Теперь нам нужно настроить периодическое выполнение скрипта **ipset-DOS-SRC-refresh.sh**.
Создадим для этого файл задачи cron:
sudo touch /etc/cron.d/ipset-DOS-SRC-refresh
sudo nano /etc/cron.d/ipset-DOS-SRC-refresh
Наполним его содержимым таким образом, чтобы наш скрипт выполнялся раз в минуту:
#
# Regular cron job for ipset chain DOS-SRC update
#
*/5 * * * * root /etc/ipset/ipset-DOS-SRC-refresh.sh
Через 10 минут проверим по логу, что наш скрипт успешно дёргается планировщиком cron
sudo grep CRON /var/log/syslog
В логе должны присутствовать записи о выполнении скрипта через заданные нами интервалы времени:
Mar 22 11:45:01 WEB-SERVER CRON[1557]: (root) CMD (/etc/ipset/ipset-DOS-SRC-refresh.sh)
Mar 22 11:50:01 WEB-SERVER CRON[1623]: (root) CMD (/etc/ipset/ipset-DOS-SRC-refresh.sh)
Mar 22 11:55:01 WEB-SERVER CRON[1677]: (root) CMD (/etc/ipset/ipset-DOS-SRC-refresh.sh)
\\
== Проверяем сохранение цепочек ipset при перезагрузке системы ==
Для проверки можно вручную добавить какой-то IP в созданную нами цепочку ipset, а затем посмотреть состояние всех цепочек ipset:
sudo ipset -A DOS-SRC 111.111.111.111
sudo ipset -L
После этого перезагружаем сервер, чтобы убедиться в том, что правила успешно создаются в iptables и ipset в процессе загрузки системы.
Для удаления конкретного IP из цепочки ipset можно воспользоваться командой:
sudo ipset del DOS-SRC 111.111.111.111
\\
== Проверяем работу механизма автоматической блокировки ==
Воспользуемся утилитой hping3, чтобы пофлудить на наш сервер по известному порту (предполагается что порт открыт) пакетами TCP SYN. Разумеется, флуд нужно выполнять с другого внешнего IP, отличного от IP нашего сервера.
Пример использования:
sudo hping3 -i u1 -S -p 80 11.22.33.44
где:
S - отсылка флага SYN
p 80 - номер атакуемого порта
i u1 - интервал в 1 микросекунду между отправляемыми пакетами.
Согласно нашим настройкам, не более чем через 5 минут после начала атаки на нашем сервере в цепочке ipset должен будет появиться IP адрес злоумышленника, и как следствие, любой трафик с него будет заблокирован. Напомню, что проверить текущее состояние цепочек ipset, выполним:
sudo ipset -L
\\
==== Учётная запись root ====
Если ОС Ubuntu на вашем сервере развёрнута не вами самостоятельно, а вы взяли готовый шаблон преднастроенной виртуальной машины у хостера, то есть [[http://anosov.me/2011/07/five-simple-steps-for-ssh-protect-in-ubuntu/|рекомендация]] перед началом использования системы убедиться в том, что учётная запись **root** выключена. Некоторые хостинг провайдеры могут включать эту учётную запись в Ubuntu.
Проверить состояние можно в файле **/etc/shadow**. Если учётная запись включена (не имеет признака "!"), выключить её можно командой:
sudo passwd -l root
\\
==== Дополнительные источники информации ====
* [[https://www.opennet.ru/base/sys/sysctl_linux.txt.html|OpenNET - Описание некоторых sysctl переменных ядра Linux (sysctl proc linux kernel tune)]]
* [[https://ru.wikibooks.org/wiki/Iptables]|Викиучебник - Iptables]]
* [[http://serverfault.com/questions/245711/iptables-tips-tricks|serverfault.com - iptables Tips & Tricks]]
* [[https://romantelychko.com/blog/1300/|Роман Теличко - Настройка Linux для высоконагруженных проектов и защиты от DDoS]]
* [[http://www.ussr.kiev.ua/ru/ddos|Блокнот ITшника - Методы борьбы с DoS/DDoS атаками]]
* [[https://debian.pro/510|Debian.pro - iptables+geoip. Баним по странам через iptables. Установка iptables-geoip/netfilter-geoip в Debian Squeeze]]
* [[http://diff.org.ua/archives/2097|diff.org.ua - Ubuntu 14.04 — Iptables TARPIT]]
* https://defcon.ru/network-security/2996/
----
{{:user:blogroot.png?50&nolink |}} Автор первичной редакции:\\ [[user:blogroot|Алексей Максимов]] \\ Время публикации: 22.03.2016 16:14
{{tag>Linux Ubuntu "Ubuntu 14.04" "14.04 LTS" "Ubuntu Server" Security iptables ipset netstat DDoS DoS sysctl Flood "UDP flood" "SYN flood" "TCP flood"}}
~~DISCUSSION~~