===== Настройка веб-сервера на базе стека 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~~