Создаем защиту от DDoS при помощи SynCookied своими руками.

Нередко встречаются ситуации когда у проекта есть своя сильная команда программистов и администраторов, которым по силам написать индивидуальное решение, с учетом тонкой специфика движка сайта, для защиты от DDoS не прибегая к специальным сервисам. В наших предыдущих материалах  мы  уже рассмотрели некоторые приемы создания защиты для своего сервера от различных атак, в том числе популярной атаки UDP Amplifications.

Сегодня мы рассмотрим еще один универсальный способ защиты, который поможет оградить ваш сервер от большинства не слишком сложных DDoS атак. Речь пойдет о прозрачной фильтрации трафика при помощи Syncookied, которое изначально предполагалось только для защиты от syn, ack, data flood, но потом переросло в достаточно большую и обширную систему по защите от разного типа атак. Данным решением мы бы хотели поделиться со всем сообществом, так как на текущий момент аналогов ему мы не нашли (или мы о них не знаем). Есть платные решения, но стоят они очень дорого.

DDoS атаки при помощи TCP протокола.

DDOS атаки бывают разные, как и их классификации. Атаки могут забивать канал, нагружать приложение, могут быть направлены на стек TCP/IP. В данном случае я хотел бы более подробно рассказать об атаке типа SynFlood (и похожих ACK, DATA), когда на конечную машину приходит много пакетов на открытие соединения.

Соединение в TCP открывается так называемым «тройным рукопожатием», для установки соединения сервер пассивно ожидает входящего пакета (выполнив системные вызовы LISTEN и ACCEPT).

  • Клиент посылает специальный пакет с флагом SYN, не содержащим данные, в котором передается начальный порядковый номер передающей последовательности (далее SEQ от клиента к серверу) и могут передаваться дополнительные опции TCP для согласования параметров соединения: mss, wscale, timestamp, sack_permitted
  • Сервер, получив пакет, сохраняет у себя значения SEQ и параметры TCP, полученные из SYN пакета, далее подготавливает ответный пакет, выставляя в нем флаги SYN+ACK. Сервер передает начальный номер последовательности (SEQ) от сервера к клиенту и возвращает стартовый номер последовательности принятой от клиента, прибавив к нему +1. Дополнительно в данном пакете передаются параметры соединения, которые согласует сервер.
  • Клиент, получив SYN+ACK пакет, сохраняет у себя параметры SEQ последовательности, принятой от сервера, добавляет к ней +1 и возвращает его в ответном пакете с установленным флагом ACK. C этого момента клиент предполагает, что соединение открыто.
  • После приема ACK пакета сервер открывает соединение.

Номера последовательностей — это, фактически, номера пакетов (байт в байтовом потоке), которые будут приняты или посланы, они необходимы для дальнейшей сборки данных в правильном порядке (протокол IP не гарантирует доставку пакетов в правильной последовательности), а также для идентификации потерянных или испорченных пакетов. У каждой стороны есть две последовательности: одна для передачи, одна для приема.

Основное назначение установки соединения — согласовать передающие последовательности и параметры соединения, которые указываются дополнительными опциями TCP. По RFC начальная последовательность должна быть произвольным числом, плавно увеличиваемым во времени.

Установить соединения можно и за 4 пакета, отправив отдельные пакеты c флагами SYN и ACK. Так же есть технология TCP Fast Open, о которой стоит поговорить отдельно.

На открытие соединения у сервера тратятся значительные ресурсы – принимая SYN пакет, сетевая карта (NIC) генерирует прерывание (не на группу пакетов, как обычно, а именно на каждый), далее этот пакет копируется с NIC в память системы (или сетевая может его писать сразу в RAM, используя технологию DMA), далее пакет направляется в систему фильтрации трафика (iptables) и на последнем шаге попадает в ядро. Ядру необходимо сохранить у себя в хеш-таблице трекинга соединений значения, полученные в SYN пакете — это IP:PORT принимающей и передающей стороны, принятая последовательность, отправленная последовательность, дополнительные параметры TCP. Само собой, чем больше размер таблицы и чем чаще в нее идет запись — тем медленней она работает. Суть в том, что операционной системе Linux необходимо проделать большое количество действий для открытия соединения, это было необходимо сделать для гибкости в обработке пакетов и, что еще более важно, размер таблицы трекинга соединений – не бесконечен.

О простоте обработки пакетов говорит приведенная ниже схема работы сетевого стека ядра Linux:

В стандартной системе без применения дополнительных механизмов и тюнинга сетевого стека сервер начинает умирать уже при 100к-150к SYN-пакетов в секунду.

Технология Syncookie

В 1997 году в ядро был добавлен механизм защиты, позволяющий не сохранять данные в таблице тракинга соединений, а подписывать переданную последовательность в SYN+ASK пакете через куку, которая размещается на месте опций TCP.

Подписывание выполняется на основе алгоритма SHA1, где для валидации используется метки времени и секретный ключ, генерируемый каждый раз новый при старте системы. Кука записывается в значения seq, TCP опций в поля Timestamp (с 31 по 6 байт), ECN, SACK, WScale (4 байта из 6). Тут нужно пояснить: в Timestamp с 0 по 5 байт передается метка времени, которая также участвует в процессе валидации пакета (в среднем обновляется раз в 2 минуты), то есть если ответный пакет пришел через час — он будет не валидный. Также накладывается ограничение на количество возможных значений MSS, в последних ядрах используются следующие значения:

Более подробно все аспекты можно посмотреть в коде ядра в файле syncookies.c

Данная технология позволила значительно увеличить способность системы обрабатывать SYN пакеты. В наших тестах, без особого тюнинга, система выдерживала 300к — 350к пакетов в секунду (данные приведены для сетевой карты 1G с 4 прерываниями). Но данное решение имеет недостатки в виде ограниченности выбора дополнительных параметров соединения — MSS ограничивается только 4 значениями, а также игнорировании части опций TCP.

Для включения в Linux Syncookie необходимо выполнить:

В значении 1 Syncookie включается только при переполнении таблицы тракинга соединений. Для значения по умолчанию 2048 (параметр net.ipv4.tcp_max_syn_backlog), скорей всего, Ваше приложение уже перестанет отвечать на запросы.

Следующим этапом развития этой технологии, начиная с ядра 3.12 и инструментария IPTables 1.4.21, стало добавление в iptables новой цели (target) – SYNPROXY (и аналогичный проект synsanity, сравнение можно посмотреть тут ), смысл которой – выполнение все тех же действий, исключая SYN пакеты из тракинга соединений, что позволяет миновать много дополнительных действий и обрабатывать пакеты в сетевом фильтре, а не в ядре. На данной технологии и адекватной сетевой карте можно обрабатывать 1-3М (и более) пакетов в секунду.

На OpenNet есть статья по настройке IPTables + SynProxy.

Не так давно в ядро были добавлены патчи от Eric Dumazet, значительно повышающие производительность сетевого стека. По заявленным тестам позволяющие обрабатывать до 6М пакетов в секунду. За проделанную работу по улучшению сетевой подсистемы ядра хочется сказать огромное спасибо.

Технология SynProxy

Защищаться на конечном сервере не всегда удачная идея, проблем может быть много — начиная от слабого железа и заканчивая полосой пропускания, если, например, сервер подключен 1G, а на него идет 2G. Подключать все сервера 10G – достаточно накладное занятие.

Такие компании как F5, Arbor, Juniper и большинство фирм по защите от DDOS реализовали технологию SynProxy. Фактически фаерволы представляются конечной машиной и отвечают SynCookie на каждый SYN пакет, при этом для увеличения производительности не всегда используется SHA1 (в наших тестах мы использовали XOR и добивались колоссальной производительности в расчете на одно ядро).

Проблема в том, что кука генерируется с использованием невалидного с точки зрения защищаемого сервера секретного ключа и метки времени. Если ответный ACK пакет просто переслать на конечную машину, она разорвет соединения. Поэтому, после получения от клиента ACK пакета с валидной кукой (валидность проверяет фаервол), необходимо симулировать открытие соединения от имени конечной машины уже без использования syncookie. При этом номера последовательностей, сохраненные на клиенте и передаваемые сервером, будут разные. В задачи фаервола будет входить замена данных последовательностей в каждом пакете от клиента к серверу и от сервера к клиенту.

Этот метод дает некоторые неоспоримые преимущества:

  • нет необходимости использовать тяжелый алгоритм SHA1
  • любые невалидные пакеты вне соединений не будут доходить на сервер (то есть фактически на 4 уровне OSI сервер полностью под защитой)
  • защищаемый сервер может работать под любой OS и даже не знать, что на него идет атака. (это очень удобно для серверов, доступа к которым нет)

Но есть и недостатки:

  • все недостатки технологии Syncookie
  • обрыв всех существующих соединений при активации защиты (есть возможность избежать, если фильтровать только SYN) и ее отключении (гарантированно).
  • оборудование необходимо встраивать в разрыв, то есть через него должен проходить весь трафик к серверу и от него.

Зачем изобретать свой велосипед

Вариант с использованием SynCookie нас не устраивал – не на всех серверах есть лишние ресурсы для подсчета SHA1, не на всех стоят подходящие сетевые карты (если на сервере 50 мегабит трафика, встроенная в материнскую плату сетевая карта вполне справляется со своей задачей) и отнюдь не все сервера подключены 10 гигабитным интерфейсом. А генерировать 1,1 гигабит SYN флуда с подменой адреса отправителя не такая уж и сложная задача, с которой может справиться любой школьник, если провайдер не фильтрует исходящий трафик. Поэтому необходимо было решение, работающее не на конечном сервере.

Использование технологии SynProxy было логичным выходом, но, как оказалось, стоимость решения от вендоров, к которым мы обращались, для наших целей превышало 100 000$ и представляло больше стоимость ПО, а не железа.

Решили разобраться в проблеме более подробно и, по возможности, написать простое решение, идеально подходящее для наших задач.

Принцип работы

Мы сделали систему, которая фильтрует трафик на любой сервер в нашей сети, просто включается и настраивается (автоматически), не требует больших ресурсов и, что не менее важно, не сильно дорога в реализации.

Логичным продолжением технологии Syncookie является вынос ее за пределы сервера, для этого мы написали модуль к ядру и демон, который общается с системой фильтрации по внутренней сети, передает секретный ключ и синхронизирует метки времени, а также включает Syncookie на сервере в случае необходимости. То есть на защищаемый сервер устанавливается модуль для ядра, который создает файл /proc/tcp_secrets, и демон, который передает данные с этого файла на фаервол.

Пояснения:

Роутерв нашем случае граничный маршрутизатор MX480.
Фаерволсервер, на котором запущена система фильтрации, соединен с главным коммутатором (Juniper EX4550) двумя линками по 10G.
Защищаемый серверзащищаемый сервер, подключен линком 1G.

Физическая организация нашего стенда (атаки на канальную емкость фильтруются на роутере):
Роутер подключен в главный коммутатор линком 40G, с главного коммутатора на фаервол идет два линка по 10G (один для входящего на фаервол трафика, другой для исходящего с него) и защищаемый сервер подключен еще через несколько коммутаторов линком 1G.

В обычном состоянии роутер и защищаемый сервер общаются напрямую, в случае обнаружения атаки на роутере прописывается статическая привязка ip адреса сервера к mac адресу фаервола, после этого весь трафик, идущий на защищаемый сервер, идет на фаервол, который имеет гораздо большую полосу пропускания (10G вместо 1G). Фаервол при получении SYN пакета (через первый интерфейс) отправляет в сеть SYN-ACK пакет (через второй интерфейс) от имени защищаемого сервера (с его mac адреса и IP) с валидной с точки зрения защищаемого сервера syncookie (так как у него есть секретный ключ и метка времени от защищаемого сервера), в случае получения ACK пакета (с кукой), фаервол проверяет его валидность, затем или меняет в пакете mac адрес на mac адрес защищаемого сервера и отправляет пакет обратно в сеть, или удаляет его, если кука не валидна. Защищаемый сервер, получая ACK пакет, открывает соединения и исходящие пакеты отправляет напрямую на роутер.

На сервере, так же как и в технологии SynProxy, ведется отслеживание соединений, так как мы видим начало открытия соединения и можем считать его закрытым по timeout (в случае если его закрыл сервер).

Алгоритм отслеживания соединений следующий:

приходит ACK пакет, проверяем куку, если валидная, сохраняем по ключу 3-tuple (src-ip, dst-port, src-port) статус Established, дальше перенаправляем пакет на защищаемый сервер.
если получаем RST пакет для соединения в статусе Established — удаляем соединение.
если получаем FIN пакет — меняем статус соединения на Closing и сохраняем таймстемп.

2 раза в минуту проходим по таблице отслеживания соединений и удаляем соединения в статусе Closing, для которых закончился Timeout.

Таблица возможных состояний соединения и последовательности передаваемых пакетов:

Также на фаерволе возможны любые правила фильтрации трафика — блокировка по IP, порту, протоколу и любым другим параметрам, которые задаются в pcap-filter в конфиге и могут применяться на лету. Например, для защищаемого сервера — запрещаем весь UDP трафик, разрешаем только TCP на порты 22, 80, 443 и для этих портов включаем SynProxy. Описание конфигурационного файла будет ниже в статье.

Во время защиты сервера от атак весь входящий трафик направляется на фаервол, и с него на сервер от имени роутера идут только валидные пакеты. Пакеты с защищаемого сервера идут напрямую на роутер в обход фаервола.

То есть, фактически, система включается только тогда, когда идет атака, и состоит из четырех основных частей:

  • модуля к ядру.
  • демона на защищаемом сервере.
  • софта на фаерволе.
  • управляющего скрипта, который определяет наличие атаки, меняет конфиг на фаерволе и вносит изменения на роутере.

Данная схема позволяет:

  • Фильтровать трафик в удобном месте.
  • Не разрывать соединения после отключения защиты. Само отключение заключается в удалении статической привязки mac адреса к IP адресу защищаемого сервера на роутере, после чего трафик идет напрямую на защищаемый сервер без обработки его фаерволом.
  • Использовать относительно недорогое железо с единственной хорошей сетевой картой.

Настройка

На защищаемом сервере

  1. Установите модуль ядра tcpsecrets для доступа к tcp syncookie key и timestamp
  2. Запустите syncookied в режиме сервера: syncookied server {ip:port}. Запуск этой команды автоматически установит значение net.ipv4.tcp_syncookies в 2 (всегда) и откроет UDP на указанном ip:port

На фаерволе

1.Установите netmap и убедитесь, что он работает.

2. Запретите использование NIC offloading features на интерфейсе, который собираетесь использовать

3. Настройте привязку прерываний к ядрам процессора. В данном примере мы привязываем 12 очередей к 12 первым процессорным ядрам:

set_irq_affinity доступен по адресу: https://github.com/majek/ixgbe/blob/master/scripts/set_irq_affinity.

4. Создайте конфигурационный файл hosts.yml в рабочий директории, например:

где:

IP – IP адрес защищаемого сервера
local_ip – IP адрес и порт, на котором запущен UDP сервер на защищаемом сервере
mac – mac адрес защищаемого сервера

5. Запустите демон

6.Настройте сеть таким образом, чтобы трафик на защищаемый сервер шел на фаервол.

7. В любой момент можно изменить конфигурацию путем изменения файла host.yml и отправки демону SIGHUP.

8. Наслаждайтесь превосходной защитой от DDOS атак =)

У syncookied есть много дополнительных опций, которые влияют на работу и производительность. Cписок всех опций:

Если у Вас на сервере более одного интерфейса, Вы можете указать второй интерфейс в опции -O для разделения исходящего трафика – это значительно улучшит производительность и позволит уменьшить задержки, так как переадресуемый трафик и SYN ответы будут разделяться.

 

Дополнительная фильтрация

Есть возможность указывать дополнительные фильтры в конфигурации хоста, фильры пишутся в pcap формате, политика по умолчанию пропускать трафик. Фильры применяются до 4 уровня модели ISO. Более подробно о формате фильтров можно прочесть в man pcap-filter.

InfluxDB

И в качестве приятного бонуса – система может писать метрики в InfluxDB, что позволит наслаждаться красивыми графиками при DDOS атаке::

Тесты производительности

Самые ресурсоемкие операции – это SHA1, IP checksum и TCP checksum. Все тестирование производительности осуществлялось на процессорах Intel Xeon E5 и Intel Xeon E3. Тестовый стенд собран на машине с одним процессором Intel(R) Xeon(R) CPU E5-2680 v3 с 32 гигабайтами памяти. В качестве сетевой карты используется Intel Ethernet Controller X710.

SHA1

В ядре есть много реализаций алгоритма SHA1 — на С, на ассемблере с использованием разных инструкций. Написали небольшую программу для тестирования скорости, результаты представлены ниже:

По результатам к проекту было решено подключить код на асемблере, использующим инструкции avx. Но, ходят слухи, что intel хочет сделать аппаратную реализацию SHA.

TCP/IP checksum

Аналогичным образом тестировали TCP и IP контрольную сумму. Код представлен здесь. По результатам тестирования выбрали самый быстрый алгоритм:

Общее тестирование производительности

В отсутсвие трафика syncookied для уменьшения задержек постоянно опрашивает сетевую карту, что создает небольшую нагрузку:

Нагрузка, создаваемая фильтрацией трафика 12.755pps (теоретический предел при размере пакета 74 байта + 4 байта заголовок ethernet)

При фильтрации UDP или применении правил по портам/протоколам нагрузка будет неотличима от нагрузки в отсутствие трафика.

Фактически 10 ядер процессора Intel Xeon E5-2680v3 могут обрабатывать до 10 гигабит трафика. Один физический сервер способен обрабатывать более 40 гигабит трафика.

Исходный код проекта: https://github.com/LTD-Beget/syncookied.

 

Рейтинг материала
[Голосов: 1 Рейтинг: 5]
28 марта 2017, 06:45

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *