Перейти к содержанию

pVega

VIP
  • Публикаций

    13
  • Зарегистрирован

  • Посещение

  • Отзывы

    N/A

Репутация

2

Информация о pVega

  • Звание
    Только пришел

Посетители профиля

Блок последних пользователей отключён и не показывается другим пользователям.

  1. Компания Variti специализируется на защите от ботов и DDoS-атак, а также проводит стресс- и нагрузочное тестирование. Поскольку мы работаем как международный сервис, нам крайне важно обеспечить бесперебойный обмен информацией между серверами и кластерами в режиме реального времени. На конференции Saint HighLoad++ 2019 разработчик Variti Антон Барабанов рассказал, как мы используем UDP и Tarantool, почему взяли именно такую связку, и как нам пришлось переписывать модуль Tarantool с Lua на C. По ссылке можно также почитать тезисы доклада, а ниже под спойлером — посмотреть видео. Когда мы начали делать сервис фильтрации трафика, мы сразу решили не заниматься IP-транзитом, а защищать HTTP, API и игровые сервисы. Таким образом, мы терминируем трафик на уровне L7 в протоколе TCP и передаем его дальше. Защита на L3&4 при этом происходит автоматически. На схеме ниже представлена схема сервиса: запросы от людей проходят через кластер, то есть серверы и сетевое оборудование, а боты (показаны в виде привидения) фильтруются. Для фильтрации необходимо разбивать трафик на отдельные запросы, точно и быстро анализировать сессии и, так как мы не блокируем по IP-адресам, внутри соединения с одного IP-адреса определять ботов и людей. Что происходит внутри кластера Внутри кластера у нас расположены независимые ноды фильтрации, то есть каждая нода работает сама по себе и только со своим куском трафика. Между нодами трафик распределяется случайным образом: если от одного пользователя поступает, например, 10 соединений, то все они расходятся по разным серверам. У нас очень жесткие требования к производительности, поскольку наши клиенты находятся в разных странах. И если, к примеру, пользователь из Швейцарии заходит на французский сайт, то он уже сталкивается с 15 миллисекундами сетевой задержки из-за увеличения маршрута трафика. Поэтому мы не вправе добавлять еще 15-20 миллисекунд внутри своего центра обработки — запрос будет идти уже критично долго. К тому же, если мы будем 15-20 миллисекунд обрабатывать каждый HTTP-запрос, то простая атака объемом 20 тысяч RPS сложит весь кластер. Это, естественно, недопустимо. Еще одним требованием для нас было не просто отслеживание запроса, но и понимание контекста. Допустим, пользователь открывает веб-страницу и отправляет запрос на слэш. После этого грузится страница, и если это HTTP/1.1, то браузер открывает 10 соединений к бэкенду и в 10 потоков запрашивает статику и динамику, делает ajax-запросы и подзапросы. Если в процессе отдачи страницы вы вместо проксирования подзапроса начнете взаимодействие с браузером и попытаетесь отдать ему, скажем, JS Challenge на подзапрос, то скорее всего сломаете страницу. На самый же первый запрос можно отдавать CAPTCHA (хотя это плохо) или JS челленджи, делать редирект, и тогда любой браузер все корректно обработает. После тестирования необходимо по всем кластерам распространить информацию о том, что сессия легитимна. Если же обмена информацией между кластерами не будет, то другие ноды получат сессию с середины и не будут знать, пропускать ее или нет. Также важно оперативно реагировать на все скачки нагрузки и изменения в трафике. Если на одной ноде что-то скакнуло, значит, через 50-100 миллисекунд скачок произойдет и на всех остальных нодах. Поэтому лучше, если ноды будут знать об изменениях заранее и заранее выставят параметры защиты, чтобы на всех остальных нодах скачка не случилось. Дополнительным сервисом к защите от ботов у нас стал сервис пост-разметки: мы ставим пиксель на сайт, записываем информацию бот/человек и отдаем эти данные по API. Эти вердикты надо где-то сохранять. То есть если раньше мы говорили о синхронизации внутри кластера, то сейчас мы добавляем синхронизацию информации еще и между кластерами. Ниже показываем схему работы сервиса на уровне L7. Между кластерами После того, как мы сделали кластер, мы начали масштабироваться. Мы работаем через BGP anycast, то есть наши подсети анонсируются со всех кластеров и трафик приходит на ближайший из них. Проще говоря, из Франции запрос отправляется на кластер во Франкфурте, а из Петербурга на кластер в Москве. Кластеры при этом должны быть независимы. Сетевые потоки же допустимо независимы. Почему это важно? Предположим, человек едет на машине, работает с сайтом с мобильного интернета и пересекает определенный рубикон, после которого трафик внезапно переключается на другой кластер. Или другой кейс: маршрут трафика перестроился, потому что где-то сгорел switch или роутер, что-то упало, отключился сегмент сети. В этом случае мы снабжаем браузер (например, в куках) достаточной информацией, чтобы при переходе на другой кластер можно было сообщить необходимые параметры о пройденных или непройденных проверках. Кроме того, необходимо синхронизировать между кластерами режим защиты. Это важно в случае low volume атак, которые чаще всего проводятся под прикрытием флуда. Поскольку атаки идут параллельно, люди думают, что им сайт ломает флуд и не видят low volume атаку. Для того случая, когда low volume приходит на один кластер, а флуд на другой, и необходима синхронизация режима защиты. И как уже упоминалось, мы синхронизируем между кластерами те самые вердикты, которые накапливаются и отдаются по API. При этом вердиктов может быть много и их необходимо синхронизировать надежно. В режиме защиты можно потерять что-то внутри кластера, но никак не между кластерами. Стоит отметить, что между кластерами большой latency: в случае с Москвой и Франкфуртом это 20 миллисекунд. Здесь нельзя делать синхронные запросы, все взаимодействие должно идти в асинхронном режиме. Ниже показываем взаимодействие между кластерами. M, l, p — это некие технические параметры для обмена. U1, u2 — это разметка пользователей на нелегитимных и легитимных. Внутреннее взаимодействие между нодами Изначально, когда мы делали сервис, фильтрация на уровне L7 была запущена всего на одной ноде. Это хорошо работало для двух клиентов, но не более. При масштабировании мы хотели достичь максимальной оперативности и минимальной latency. Было важно минимизировать и затрачиваемые ресурсы CPU на обработку пакетов, так что не подошло бы взаимодействие через, например, HTTP. Также надо было обеспечить минимальный накладной расход не только вычислительных ресурсов, но и пакетрейта. Все же мы говорим о фильтрации атак, а это ситуации, в которых заведомо не хватает производительности. Обычно при построении веб-проекта достаточно х3 или х4 к нагрузке, но у нас всегда х1, поскольку всегда может прийти масштабная атака. Еще одно требование к интерфейсу взаимодействия — это наличие места, куда мы будем писать информацию и откуда потом сможем считать, в каком сейчас состоянии находимся. Не секрет, что для разработки систем фильтрации зачастую используется C++. Но к сожалению, программы, написанные на C++, иногда падают в корку. Иногда такие программы надо перезапускать, чтобы обновить, или, к примеру, потому что конфигурация не перечиталась. И если мы перезапускаем ноду под атакой, то необходимо где-то взять контекст, в котором эта нода существовала. То есть сервис должен быть не stateless, он должен помнить, что есть некое множество людей, которых мы заблокировали, которых мы проверяем. Должна быть та самая внутренняя коммуникация, чтобы сервис мог получить первичный сет информации. У нас были мысли поставить рядом некую базу данных, например, SQLite, но мы такое решение быстро отбросили, потому что странно на каждом сервере писать Input-Output, это будет плохо работать в памяти. Фактически мы работаем всего с тремя операциями. Первая функция “отправить”, причем на все ноды. Это касается, например, сообщений по синхронизации текущей нагрузки: каждая нода должна знать общую нагрузку на ресурс в рамках кластера, чтобы отслеживать пики. Вторая операция — “сохранить”, она касается вердиктов проверки. А третья операция — это комбинация “отправить всем” и “сохранить”. Здесь речь идет о сообщениях по изменению состояния, которые мы отправляем на все ноды и потом сохраняем, чтобы иметь возможность вычитать. Ниже представлена получившаяся схема взаимодействия, в которую мы должны будем добавить параметры для сохранения. Варианты и результат Какие варианты для сохранения вердиктов мы смотрели? Во-первых, мы думали о классике, RabbitMQ, RedisMQ и собственном TCP-based-сервисе. Эти решения мы отбросили, потому что они медленно работают. Тот же TCP добавляет х2 к пакетрейту. Кроме того, если мы с одной ноды отправляем сообщение на все остальные, то нам либо надо иметь очень много нод отправки, либо эта нода сможет отравлять 1/16 от тех сообщений, которые 16 машин могут отправить в нее. Понятно, что это недопустимо. В итоге, мы взяли UDP multicast, поскольку в этом случае центром отправки выступает сетевое оборудование, которое не ограничено в производительности и позволяет полностью решить проблемы со скоростью отправки и приема. Понятно, что в случае с UDP мы не думаем о текстовых форматах, а отправляем бинарные данные. Кроме того, мы сразу добавили пакетирование и базу данных. Мы взяли Tarantool, потому что, во-первых, у всех трех основателей компании был опыт работы с этой базой данных, а во-вторых, она максимально гибкая, то есть это еще и некий application сервис. Кроме того, у Tarantool есть CAPI, а возможность писать на C для нас принципиальный момент ввиду того, что для защиты от DDoS необходима максимальная производительность. Ни один же интерпретируемый язык не может обеспечить достаточную производительность, в отличие от C. На схеме ниже добавили внутрь кластера базу данных, в которой и хранятся состояния для внутренней коммуникации. Добавляем базу данных В базе данных мы храним состояние в виде лога обращений. Когда мы придумывали, как сохранить информацию, было два варианта. Можно было хранить некоторое состояние с постоянным обновлением и изменением, но это довольно сложно имплементировать. Поэтому мы использовали другой подход. Дело в том, что структура отправляемых по UDP данных унифицирована: есть тайминг, какой-то код, три-четыре поля данных. Так что мы эту структуру начали писать в space Tarantool и добавили туда запись TTL, по которой понятно, что структура устарела и ее надо удалить. Таким образом, в Tarantool накапливается лог сообщений, который мы зачищаем с заданным таймингом. Чтобы удалять старые данные, мы изначально взяли expirationd. Впоследствии нам пришлось от него отказаться, поскольку он вызывал определенные проблемы, о которых расскажем ниже. Пока что схема: на ней к нашей структуре добавились две базы данных. Как мы уже упоминали, помимо хранения состояний кластера необходимо синхронизировать еще и вердикты. Вердикты мы синхронизируем межкластерно. Соответственно надо было добавить дополнительную инсталляцию Tarantool. Использовать другое решение было бы странно, потому что Tarantool уже есть и он идеально подходит для нашего сервиса. В новую инсталляцию мы стали писать вердикты и реплицировать их с другими кластерами. При этом мы используем не master/slave, а master/master. Сейчас в Tarantool только асинхронный master/master, что для многих случаев не подходит, но для нас такая модель оптимальна. При минимальной latency между кластерами синхронная репликация помешала бы, асинхронная же проблем не вызывает. Проблемы Но проблем у нас было много. Первый блок сложностей связан с UDP: не секрет, что протокол умеет бить и терять пакеты. Мы эти проблемы решили методом страуса, то есть просто спрятали голову в песок. Все же повреждения пакетов и перестановка их местами у нас невозможны, поскольку коммуникация идет в рамках одного switch, и нет нестабильных соединений и нестабильного сетевого оборудования. Возможна проблема потери пакетов, если зависла машина, где-то возник Input-Output или перегрузилась нода. Если такое зависание произошло на небольшой период времени, скажем, на 50 миллисекунд, то это ужасно, но решается увеличенными очередями sysctl. То есть берем sysctl, настраиваем размер очередей и получаем буфер, в котором все лежит, пока нода не заработает снова. Если случится более долгое зависание, то проблемой будет потеря не связности, а части трафика, который уходит на ноду. У нас пока таких случаев просто не было. Гораздо сложнее были проблемы с асинхронной репликацией Tarantool. Изначально мы взяли не master/master, а более традиционную модель для эксплуатации master/slave. И все работало ровно до того момента, пока slave не взял на себя на длительное время нагрузку master. В итоге expirationd работал и удалял данные на master, а на slave его не было. Соответственно когда мы несколько раз переключились с master на slave и обратно, на slave накопилось столько данных, что в какой-то момент все сломалось. Так что для полноценной отказоустойчивости пришлось переключиться на асинхронную репликацию master/master. И здесь снова возникли сложности. Во-первых, ключи могут пересекаться между разными репликами. Предположим, в рамках кластера мы записали данные на один master, в этот момент соединение оборвалось, мы записали все на второй master, а после, того как произвели асинхронную репликацию, оказалось, что в space одинаковые primary key, и репликация рассыпается. Решили мы эту проблему просто: взяли модель, при которой primary key обязательно содержит имя ноды Tarantool, в которую мы пишем. Благодаря этому конфликты перестали возникать, но стала возможной ситуация, когда дублируются пользовательские данные. Это крайне редкий случай, поэтому мы им опять же просто пренебрегли. Если дублирование будет происходить часто, то у Tarantool много разных индексов, так что всегда можно сделать дедупликацию. Другая проблема касается сохранения вердиктов и возникает, когда данные, записанные на одном master, еще не оказались на другом, а на первый master уже пришел запрос. Мы, если честно, пока этот вопрос не решили и просто задерживаем вердикт. Если это недопустимо, то мы организуем некий пуш о готовности данных. Примерно так мы и справились с master/master репликацией и ее проблемами. Был блок проблем, связанных непосредственно с Tarantool, его драйверами и модулем expirationd. Спустя некоторое время после запуска, атаки к нам стали приходить каждый день, соответственно количество сообщений, которое мы сохраняем в базе для синхронизации и хранения контекста, стало очень большим. И при зачистке стало удаляться настолько много данных, что перестал справляться garbage collector. Мы эту проблему решили, написав на языке C свой модуль expirationd, который назвали IExpire. Впрочем, с expirationd осталась еще одна сложность, с которой мы пока не справились и которая заключается в том, что expirationd работает только на одном master. И если нода с expirationd упадет, то кластер потеряет критичную функциональность. Допустим, мы чистим все данные старше одного часа — понятно, что если нода пролежит, скажем, пять часов, то количество данных будет x5 к обычному. И если в этот момент придет крупная атака, то есть совпадут два плохих кейса, то кластер упадет. Мы пока не знаем, как с этим бороться. Наконец, оставались сложности с драйвером Tarantool для C. Когда у нас ломался сервис (например, из-за race condition), то на поиск причины и отладку уходило много времени. Поэтому мы просто написали свой драйвер Tarantool. На имплементирование протокола вместе с тестированием, отладкой и запуском в продакшене у нас ушло пять дней, но у нас уже был готов свой код для работы с сетью. Проблемы снаружи Напомним, что у нас уже готова репликация Tarantool, мы уже умеем синхронизировать вердикты, но инфраструктуры для передачи между кластерами сообщений об атаках или проблемах пока нет. По поводу инфраструктуры у нас было много разных мыслей, в том числе мы думали про написание своего TCP-сервиса. Но все же есть модуль Tarantool Queue от команды Tarantool. К тому же, у нас уже был Tarantool c межкластерной репликацией, были подкручены “дырки”, то есть не надо было ходить к админам и просить открыть порты или прогонять трафик. Опять же, была готова интеграция в софт фильтрации. Оставалась сложность с принимающей нодой. Допустим, есть n независимых нод внутри кластера и надо выбрать ту, которая будет взаимодействовать с очередью на запись. Потому что иначе будет отправляться 16 сообщений или 16 раз будет вычитываться из очереди одно и то же сообщение. Эту проблему мы решили просто: мы прописываем в space Tarantool ответственную ноду, и если нода сгорает, то мы просто меняем space, если не забудем. Но если забудем, то это проблема, которую мы тоже хотим в будущем решить. Ниже представлена уже детальная схема кластера с интерфейсом взаимодействия. Что хочется улучшить и добавить Во-первых, мы хотим выложить в open source IExpire. Нам кажется, это полезный модуль, потому что он позволяет делать все то же самое, что и expirationd, но с практически нулевым overhead. Туда стоит добавить некий сортировочный индекс, чтобы удалять только самые старые tuple. Пока что мы этого не сделали, поскольку основная операция в Tarantool для нас — это “запись”, и лишний индекс повлечет лишнюю нагрузку из-за его поддержки. Мы также хотим переписать большинство методов на CAPI, чтобы избежать складывания базы данных. Остается вопрос с выбором логического мастера, но кажется, эту проблему решить полностью невозможно. То есть в случае, если нода с expirationd упадет, остается только вручную выбирать другую ноду и запускать expirationd на ней. Автоматически это делать вряд ли получится, поскольку репликация асинхронная. Хотя мы, наверное, посоветуемся на этот счет с командой Tarantool. В случае экспоненциального роста кластеров нам также придется просить помощи у команды Tarantool. Дело в том, что для Tarantool Queue и межкластерного сохранения вердиктов используется репликация “все-ко-всем”. Это хорошо работает, пока кластеров, например, три, но когда их становится 100, то количество соединений, за которыми надо следить, будет невероятно большим, и постоянно будет что-то ломаться. Во-вторых, не факт, что Tarantool такую нагрузку выдержит. Выводы Первые выводы касаются UDP multicast и Tarantool. Multicast не надо его бояться, его использование внутри кластера — это хорошо, правильно и быстро. Есть много кейсов, когда идет постоянная синхронизация состояний, и через 50 миллисекунд уже неважно, что произошло ранее. И в этом случае, скорее всего, потеря одного состояния проблемой не будет. Так что использование UDP multicast оправданно, поскольку вы не ограничиваете производительность и получаете оптимальный пакетрейт. Второй момент — Tarantool. Если у вас сервис на go, php и так далее, то скорее всего Tarantool применим как есть. Но если у вас большие нагрузки, то понадобится напильник. Но будем честны, напильник в таком случае нужен вообще для всего: и для Oracle, и для PostgeSQL. Конечно, есть мнение, что не надо изобретать велосипед, и если у вас маленькая команда, то стоит брать готовое решение: Redis для синхронизации, стандартный go, python и так далее. Это неправда. Если вы уверены, что новое решение вам необходимо, если вы поработали с open source, выяснили, что вам ничего не подходит, или точно знаете заранее, что даже нет смысла пробовать, то свое решение пилить полезно. Другой разговор, что важно вовремя остановиться. То есть не надо писать свой Tarantool, не надо реализовывать свой обмен сообщениями, и если вам просто нужен брокер, возьмите уже Redis, и будет вам счастье. Ссылка на нашу статью: https://habr.com/ru/company/variti/blog/459264/
  2. DDoS-атаки остаются одной из наиболее обсуждаемых тем в сфере информационной безопасности. При этом далеко не все знают, что ботовый трафик, который и является инструментом для таких атак, влечет множество других опасностей для онлайн-бизнеса. С помощью ботов злоумышленники могут не только вывести сайт из строя, но и украсть данные, исказить бизнес-метрики, увеличить рекламные расходы, испортить репутацию площадки. Разберем угрозы более детально, а также напомним про базовые способы защиты. Парсинг Боты парсят (то есть собирают) данные на сторонних сайтах постоянно. Они крадут контент, чтобы потом публиковать его без ссылок на источник. При этом размещение скопированного контента на сторонних площадках опускает ресурс-источник в поисковой выдаче, что означает сокращение аудитории, продаж и рекламных доходов сайта. Боты также отслеживают цены, чтобы продавать товары дешевле и уводить клиентов. Покупают различные вещи, чтобы перепродать дороже. Могут создавать ложные заказы, чтобы загрузить логистические ресурсы и сделать товары недоступными для пользователей. Парсинг значительно сказывается на работе онлайн-магазинов, особенно тех, у кого основной трафик поступает с площадок-агрегаторов. Злоумышленники после парсинга цен устанавливают стоимость товара незначительно ниже исходной, и это позволяет им заметно подняться в поисковой выдаче. Туристические порталы тоже часто подвергаются ботовым атакам: у них крадут сведения о билетах, турах и гостиницах. В общем, мораль проста: если на вашем ресурсе есть уникальный контент, боты уже выехали к вам. Заметить парсинг можно по внезапным всплескам трафика, а также отслеживая ценовую политику конкурентов. Если другие сайты мгновенно копируют у себя ваши изменения в стоимости — значит, тут скорее всего замешаны боты. Накрутки Накрутки показателей — это сопутствующий эффект от присутствия ботов на сайте. Каждое действие ботов отражается на бизнес-метриках. Поскольку доля нелегитимного трафика ощутима, решения, основанные на аналитике ресурса, часто бывают ошибочными. Маркетологи изучают, как посетители используют ресурс и делают покупки. Смотрят на показатель конверсии и лиды и определяют ключевые воронки продаж. Компании также проводят A/B тесты и в зависимости от результатов пишут стратегии для работы сайта. Боты же влияют на все эти показатели, что ведет к нерациональным решениям и излишним маркетинговым затратам. Злоумышленники могут использовать ботов и для того, чтобы повлиять на репутацию площадок, в том числе соцсетей. Такая же ситуация и с сайтами для онлайн-голосований, где боты часто накручивают показатели, чтобы победил нужный злоумышленникам вариант. Как можно обнаружить накрутки: Проверяйте аналитику. Резкий и неожиданный рост какого-либо показателя, например, попыток логина, часто означает ботовую атаку. Отслеживайте изменения в происхождении трафика. Бывает, что на сайт приходит необычно большое количество запросов из необычных стран — это странно, если вы не таргетировали на них кампании. DDoS-атаки Многие слышали о DDoS-атаках или даже сталкивались с ними. Стоит отметить, что ресурс не всегда выводится из строя с помощью высокого трафика. Атаки на API часто низкочастотны, и в то время как приложение отказывает, firewall и балансировщик нагрузки работают как ни в чем не бывало. Утроение трафика на главную страницу может никак не сказаться на работоспособности сайта, но такая же нагрузка напрямую на страницу с корзиной приводит к проблемам, поскольку приложение начинает посылать множественные запросы ко всем компонентам, задействованным в транзакциях. Как обнаружить атаки (первые два пункта могут показаться очевидными, но не стоит ими пренебрегать): Покупатели жалуются, что сайт не работает. Сайт или отдельные страницы работают медленно. Резко растет трафик на отдельных страницах, появляется большое количество запросов в корзину или на страницу оплаты. Взлом личных кабинетов BruteForce, или перебор паролей, организуется с помощью ботов. Для взлома используются утекшие базы данных. В среднем, пользователи придумывают не более пяти вариантов паролей для всех онлайн-аккаунтов — и варианты легко подбираются ботами, которые проверяют миллионы комбинаций в кратчайшее время. Затем злоумышленники могут перепродать актуальные комбинации логинов и паролей. Также хакеры могут завладеть личными кабинетами и затем использовать их в своих интересах. Например, вывести накопленные бонусы, украсть купленные билеты на мероприятия — в общем, вариантов дальнейших действий множество. Распознать BruteForce не слишком сложно: о том, что хакеры пытаются взломать аккаунт, говорит необычно высокое количество неуспешных попыток логина. Хотя бывает, что злоумышленники отправляют и небольшое количество запросов. Скликивание Скликивание рекламных объявлений ботами может привести к значительным убыткам компаний, если его не заметить. Во время атаки боты переходят по размещенным на сайте объявлениям и тем самым ощутимо влияют на метрики. Рекламодатели, очевидно, рассчитывают, что размещенные на площадках баннеры и видеоролики увидят реальные пользователи. Но поскольку число показов ограничено, реклама, из-за ботов, демонстрируется все меньшему числу людей. Сами же сайты хотят за счет показов рекламы увеличить свою прибыль. А рекламодатели, если видят ботовый трафик, снижают объем размещений на площадке, что ведет и к убыткам, и к ухудшению репутации площадки. Эксперты выделяют следующие типы рекламного фрода: Ложные просмотры. Боты посещают множество страниц сайта и генерируют нелегитимные просмотры рекламы. Кликфрод. Боты переходят по рекламным ссылкам в поиске, что ведет к росту расходов на поисковую рекламу. Ретаргетинг. Боты перед скликиванием посещают множество легитимных площадок, чтобы создать cookie-файл, который стоит дороже для рекламодателей. Как обнаружить скликивание? Обычно после очистки трафика от фрода показатель конверсии снижается. Если вы видите, что объем переходов по баннерам выше ожидаемого, то это говорит о присутствии ботов на сайте. Другими показателями нелегитимного трафика могут быть: Рост кликов по рекламным объявлениям при минимальной конверсии. Конверсия снижается, хотя содержание рекламы не менялось. Множественные клики с одного IP-адреса. Низкая доля вовлечения пользователей (в том числе большое количество отказов) при росте кликов. Поиск уязвимостей Тестирование на уязвимости выполняется автоматическими программами, которые ищут слабые места сайта и API. Среди популярных инструментов — Metasploit, Burp Suite, Grendel Scan и Nmap. Сканировать сайт могут как специально нанятые компанией сервисы, так и злоумышленники. Площадки договариваются со специалистами по взлому, чтобы проверить свою защиту. IP-адреса аудиторов в таком случае заносятся в white-листы. Злоумышленники же тестируют сайты без предварительной договоренности. В дальнейшем хакеры используют результаты проверок для своих целей: к примеру, они могут перепродать информацию о слабых местах площадки. Бывает, что ресурсы сканируются не целенаправленно, а в рамках эксплуатирования уязвимости сторонних ресурсов. Возьмем WordPress: если в какой-либо версии обнаружен баг, боты ищут все площадки, которые используют эту версию. Если ваш ресурс попал в такой список, можно ждать визита хакеров. Как обнаружить ботов? Для поиска слабых мест сайта злоумышленники сначала проводят разведку, что ведет к росту подозрительной активности на площадке. Фильтрация ботов на этом этапе поможет избежать последующих атак. Хотя ботов и сложно обнаружить, тревожным сигналом могут стать отправляемые с одного IP-адреса запросы ко всем страницам сайта. Стоит обратить внимание и на рост запросов к несуществующим страницам. Спам Боты могут заполнять формы сайта «мусорным» контентом без вашего ведома. Спамеры оставляют комментарии и отзывы, создают фейковые регистрации и заказы. Классический метод борьбы с ботами, CAPTCHA, в этом случае неэффективен, поскольку раздражает реальных пользователей. К тому же, боты научились обходить такие инструменты. Чаще всего спам безвреден, однако бывает, что боты предлагают сомнительные услуги: размещают объявления о продаже поддельных вещей и лекарств, продвигают ссылки на порносайты и уводят пользователей на мошеннические ресурсы. Как обнаружить ботов-спамеров: Если на вашем сайте появился спам, то скорее всего его собственно боты и размещают. В вашей почтовой рассылке много недействительных адресов. Боты часто оставляют несуществующие е-мейлы. Ваши партнеры и рекламодатели жалуются, что с вашего сайта приходят спам-лиды. Из этой статьи может показаться, что бороться с ботами своими силами сложно. На самом деле, так оно и есть, и лучше доверить защиту сайта профессионалам. Даже крупные компании часто не в силах самостоятельно отслеживать нелегитимный трафик и тем более фильтровать его, поскольку это требует значительной экспертизы и больших расходов на IT-команду. Variti защищает сайты и API от всех видов ботовых атак, включая фрод, DDoS, скликивание и парсинг. Собственная технология Active Bot Protection позволяет без CAPTCHA и блокировки IP-адресов выявлять и отсекать ботов. Ссылка на нашу статью: https://habr.com/ru/company/variti/blog/457276/
  3. Компания Variti разрабатывает защиту от ботов и DDoS-атак, а также проводит стресс- и нагрузочное тестирование. На конференции HighLoad++ 2018 мы рассказывали, как обезопасить ресурсы от различного вида атак. Если коротко: изолируйте части системы, используйте облачные сервисы и CDN и регулярно обновляйтесь. Но без специализированных компаний с защитой вы все равно не справитесь Перед прочтением текста можете ознакомиться с короткими тезисами на сайте конференции. А если вы не любите читать или просто хотите посмотреть видео, запись нашего доклада ниже под спойлером. Многие компании уже умеют делать нагрузочные тестирования, но не все делают стресс-тестирования. Некоторые наши заказчики думают, что их сайт неуязвим, потому что у них есть highload система, и она хорошо защищает от атак. Мы же показываем, что это не совсем правда. Разумеется, перед проведением тестов мы получаем разрешение от заказчика, с подписью и печатью, и с нашей помощью DDoS-атаку сделать ни на кого нельзя. Тестирование проводится в выбранное заказчиком время, когда посещаемость его ресурса минимальна, а проблемы с доступом не отразятся на клиентах. Кроме того, поскольку в процессе тестирования всегда может пойти что-то не так, у нас есть постоянный контакт с заказчиком. Это позволяет не только сообщать о достигнутых результатах, но и что-то менять в ходе тестирования. При завершении тестирования мы всегда составляем отчет, в котором указываем на обнаруженные недостатки и даем рекомендации по устранению слабых мест сайта. Как мы работаем При проведении тестирования мы эмулируем ботнет. Поскольку мы работаем с клиентами, которые не располагаются в наших сетях, то для того, чтобы тест не закончился на первой же минуте из-за срабатывания лимитов или защиты, мы подаем нагрузку не с одного IP, а с собственной подсети. Плюс, для создания значительной нагрузки у нас есть свой достаточно мощный тестовый сервер. Постулаты Много — не значит хорошо Чем меньшей нагрузкой мы сможем довести ресурс до отказа, тем лучше. Если получится сделать так, что сайт прекратит функционировать от одного запроса в секунду, или даже от одного запроса в минуту, это прекрасно. Потому что по закону подлости пользователи или злоумышленники случайно попадут именно в эту уязвимость. Частичный отказ лучше, чем полный Мы всегда советуем делать системы гетерогенными. Причем разделять их стоит именно на физическом уровне, а не только контейниризацией. В случае физического разделения, даже если на сайте что-то откажет, то велика вероятность, что он не прекратит работу полностью, и у пользователей сохранится доступ хотя бы к части функционала. Правильная архитектура — основа устойчивости Отказоустойчивость ресурса и его способность выдерживать атаки и нагрузки должны закладываться на этапе проектирования, фактически на этапе рисования первых блок-схем в блокноте. Потому что если закрадываются фатальные ошибки, исправить их в дальнейшем можно, но очень сложно. Хорошим должен быть не только код, но и конфиг Многие думают, что хорошая команда разработки это гарантия отказоустойчивости сервиса. Хорошая команда разработки действительно необходима, но должна быть еще и хорошая эксплуатация, хороший DevOps. То есть нужны специалисты, которые правильно сконфигурируют Linux и сеть, правильно напишут конфиги в nginx, настроят лимиты и прочее. В противном случае ресурс будет хорошо работать только на тесте, а в продакшене в какой-то момент все сломается. Отличия нагрузочного и стресс-тестирования Нагрузочное тестирование позволяет выявить пределы функционирования системы. Стресс-тестирование направлено на поиск слабых мест системы и используется для того, чтобы эту систему сломать и посмотреть, как она будет вести себя в процессе отказа тех или иных частей. При этом при характер нагрузки обычно остается неизвестным для заказчика до начала стресс-тестирования. Отличительные черты L7 атак Виды нагрузки мы обычно делим на нагрузки на уровне L7 и L3&4. L7 — это нагрузка на уровне приложения, чаще всего под ней понимают только HTTP, мы же подразумеваем любую нагрузку на уровне протокола TCP. У L7 атак есть определенные отличительные черты. Во-первых, они приходят непосредственно в приложение, то есть отразить их сетевыми средствами вряд ли получится. Такие атаки задействуют логику, и за счет этого очень эффективно и при небольшом трафике потребляют ЦПУ, память, диск, базу данных и прочие ресурсы. HTTP Flood В случае любой атаки нагрузку проще создать, чем обработать, и в случае с L7 это тоже верно. Трафик атаки не всегда просто отличить от легитимного, и чаще всего это удается сделать по частотности, но если все спланировано грамотно, то по логам понять, где атака, а где легитимные запросы, невозможно. В качестве первого примера рассмотрим атаку HTTP Flood. Из графика видно, что обычно такие атаки очень мощные, в примере ниже пиковое число запросов превосходило 600 тысяч в минуту. HTTP Flood — это самый простой способ создать нагрузку. Обычно для него берется какой-то инструмент нагрузочного тестирования, например, ApacheBench, и задаются запрос и цель. При таком простом подходе велика вероятность нарваться на кеширование сервера, но его легко обойти. Например, добавив случайные строки в запрос, что вынудит сервер постоянно отдавать свежую страницу. Также не стоит забывать про user-agent в процессе создания нагрузки. Многие user-agent популярных инструментов тестирования фильтруются системными администраторами, и в таком случае нагрузка может просто не дойти до бэкенда. Значительно улучшить результат можно, вставляя в запрос более или менее валидный заголовок из браузера. При всей простоте атаки HTTP Flood имеют и свои недостатки. Во-первых, для создания нагрузки требуются большие мощности. Во-вторых, такие атаки очень легко обнаруживаются, особенно если идут с одного адреса. В итоге, запросы сразу же начинают фильтроваться либо системными администраторами, либо даже на уровне провайдера. Что искать Чтобы снизить количество запросов в секунду и при этом не потерять в эффективности, нужно проявить немного фантазии и исследовать сайт. Так, нагружать можно не только канал или сервер, но и отдельные части приложения, например, базы данных или файловые системы. Также можно поискать места на сайте, которые делают большие вычисления: калькуляторы, страницы с подбором продуктов и прочее. Наконец, часто бывает, что на сайте есть некий php-скрипт, который генерирует страницу из нескольких сотен тысяч строк. Такой скрипт тоже в значительной степени нагружает сервер и может стать мишенью для атаки. Где искать Когда мы сканируем ресурс перед проведением тестирования, то в первую очередь смотрим, конечно, на сам сайт. Мы ищем всевозможные поля ввода, тяжелые файлы — в общем все, что может создать проблемы ресурсу и замедляет его работу. Здесь помогают банальные средства разработки в Google Chrome и Firefox, показывающие время ответов страницы. Также мы сканируем поддомены. Например, есть некий онлайн-магазин, abc.com, и у него есть поддомен admin.abc.com. Скорее всего, это админка с авторизацией, но если в нее пустить нагрузку, то она может создать проблемы для основного ресурса. У сайта может быть поддомен api.abc.com. Скорее всего, это ресурс для мобильных приложений. Приложение можно найти в App Store или Google Play, поставить специальную точку доступа, препарировать API и зарегистрировать тестовые аккаунты. Проблема в том, что зачастую люди думают, что все, что защищено авторизацией, неуязвимо для атак на отказ в обслуживании. Якобы авторизация это лучшая CAPTCHA, но это не так. Сделать 10-20 тестовых аккаунтов просто, а создав их, мы получаем доступ к сложному и неприкрытому функционалу. Естественно, мы смотрим на историю, на robots.txt и WebArchive, ViewDNS, ищем старые версии ресурса. Иногда бывает так, что разработчики выкатили, скажем, mail2.yandex.net, а старая версия, mail.yandex.net, осталась. Этот mail.yandex.net перестает поддерживаться, на него не отводятся ресурсы разработки, но он продолжает потреблять базу данных. Соответственно с помощью старой версии можно эффективно задействовать ресурсы бэкенда и всего того, что стоит за версткой. Конечно, так происходит не всегда, но с подобным мы сталкиваемся все равно довольно часто. Естественно, мы препарируем все параметры запроса, структуру cookie. Можно, скажем, запулить в JSON массив внутри cookie какое-то значение, создать большую вложенность и заставить ресурс работать неразумно долго. Нагрузка в поиск Первое, что приходит в голову при исследовании сайта, это нагрузить базу данных, поскольку поиск есть почти у всех, и почти у всех он, к сожалению, защищен плохо. Почему-то разработчики не уделяют поиску достаточное внимание. Но тут есть одна рекомендация — не стоит делать однотипные запросы, потому что можно столкнуться с кешированием, как и в случае с HTTP flood. Делать случайные запросы в базу данных тоже не всегда эффективно. Гораздо лучше создать список ключевых слов, которые относятся к поиску. Если возвращаться к примеру интернет-магазина: допустим, сайт торгует автомобильной резиной и позволяет задавать радиус шин, тип машины и прочие параметры. Соответственно комбинации релевантных слов заставят базу данных работать в намного более сложных условиях. Кроме того, стоит использовать пагинацию: поиску гораздо сложнее отдать предпоследнюю страницу выдачи, чем первую. То есть с помощью пагинации можно немного разнообразить нагрузку. На примере ниже показываем нагрузку в поиск. Видно, что с первой же секунды теста на скорости десять запросов в секунду сайт лег и не отвечал. Если поиска нет? Если поиска нет, то это не значит, что сайт не содержит в себе других уязвимых полей ввода. Таким полем может оказаться авторизация. Сейчас разработчики любят делать сложные хеши, чтобы защитить базу логинов от атаки по радужным таблицам. Это хорошо, но такие хеши потребляют большие ресурсы CPU. Большой поток ложных авторизаций приводит к отказу процессора, и как следствие, на выходе сайт перестает работать. Присутствие на сайте всевозможных форм для комментариев и обратной связи — это повод отправить туда очень большие тексты или просто создать массовый флуд. Порой сайты принимают вложенные файлы, в том числе в формате gzip. В таком случае, мы берем файл размером 1Тб, с помощью gzip сжимаем его до нескольких байт или килобайт и отправляем на сайт. Дальше он разархивируется и получается очень интересный эффект. Rest API Хотелось бы уделить немного внимания таким популярным нынче сервисам, как Rest API. Защитить Rest API гораздо сложнее, чем обычный сайт. Для Rest API не работают даже банальные способы защиты от перебора паролей и прочей нелигитимной активности. Rest API очень просто сломать, потому что он обращается непосредственно к базе данных. При этом вывод такого сервиса из строя влечет за собой достаточно тяжелые последствия для бизнеса. Дело в том, что на Rest API обычно завязан не только главный сайт, но и мобильное приложение, какие-то внутренние бизнес-ресурсы. И если это все падает, то эффект гораздо сильнее, чем в случае с выходом из строя простого сайта. Нагрузка на тяжелый контент Если нам предлагают тестировать какое-то обычное одностраничное приложение, лендинг, сайт-визитку, у которых нет сложного функционала, мы ищем тяжелый контент. Например, большие картинки, которые отдает сервер, бинарные файлы, pdf-документацию, — мы пробуем все это выкачивать. Такие тесты хорошо грузят файловую систему и забивают каналы, и поэтому эффективны. То есть даже если вы не положите сервер, скачивая большой файл на небольших скоростях, то вы просто забьете канал целевого сервера и тогда наступит отказ в обслуживании. На примере такого теста видно, что на скорости 30 RPS сайт перестал отвечать, либо выдавал 500-е ошибки сервера. Не стоит забывать и про настройку серверов. Часто можно встретить, что человек купил виртуалку, поставил туда Apache, настроил все по умолчанию, расположил php-приложение, и ниже можно увидеть результат. Здесь нагрузка шла в корень и составляла всего 10 RPS. Мы подождали 5 минут, и сервер упал. До конца, правда, неизвестно, почему он упал, но есть предположение, что он просто объелся памяти, и поэтому перестал отвечать. Wave based В последние год-два достаточно популярными стали волновые атаки. Это связано с тем, что многие организации покупают те или иные железки для защиты от DDoS, которые требуют определенного времени накопления статистики для начала фильтрации атаки. То есть они не фильтруют атаку в первые 30-40 секунд, потому что накапливают данные и обучаются. Соответственно в эти 30-40 секунд на сайт можно запустить столько, что ресурс будет лежать длительное время, пока не разгребутся все запросы. В случае с атакой ниже был интервал 10 минут, после чего прилетела новая, видоизмененная порция атаки. То есть защита обучилась, запустила фильтрацию, но прилетела новая, совершенно другая порция атаки, и защита снова начала обучение. Фактически, фильтрация перестает работать, защита становится неэффективной, и сайт недоступен. Для волновых атак характерны очень высокие значения на пике, она может достигать ста тысяч или миллиона запросов в секунду, в случае с L7. Если говорить про L3&4, то там могут быть сотни гигабит трафика, или, соответственно, сотни mpps, если считать в пакетах. Проблема же таких атак в синхронизации. Атаки идут с ботнета, и для того, чтобы создать очень большой разовый пик, требуется высокая степень синхронизации. И эта координация не всегда получается: иногда на выходе получается какой-то параболический пик, который выглядит довольно жалко. Не HTTP единым Помимо HTTP на уровне L7, мы любим эксплуатировать и другие протоколы. Как правило, у обычного веб-сайта, тем более у обычного хостинга, наружу торчат почтовые протоколы и MySQL. Почтовые протоколы подвержены нагрузкам в меньшей степени, чем базы данных, но их тоже можно нагружать достаточно эффективно и на выходе получать перегруженный CPU на сервере. Мы вполне реально с помощью уязвимости SSH 2016 года добивались успеха. Сейчас эта уязвимость почти у всех поправлена, но это не значит, что в SSH нельзя подавать нагрузку. Можно. Просто подается огромная нагрузка авторизаций, SSH съедает почти весь CPU на сервере и дальше веб-сайт складывается уже от одного-двух запросов в секунду. Соответственно эти один-два запроса по логам никак нельзя отличить от легитимной нагрузки. Остаются актуальными и множество соединений, которые мы открываем в серверах. Раньше этим грешил Apache, сейчас этим фактически грешит и nginx, поскольку он часто настраивается по дефолту. Количество соединений, которые nginx может держать открытыми, лимитировано, соответственно мы открываем это количество соединений, новое соединение nginx уже не принимает, и на выходе сайт не работает. Наш тестовый кластер обладает достаточным CPU, чтобы атаковать SSL handshake. В принципе, как показывает практика, ботнеты тоже иногда любят это делать. С одной стороны, понятно, что без SSL не обойтись, потому что выдача Google, ранжирование, безопасность. С другой стороны, у SSL, к сожалению, есть проблема с CPU. L3&4 Когда мы говорим об атаке на уровнях L3&4, мы говорим, как правило, об атаке на уровне канала. Такая нагрузка почти всегда отличима от легитимной, если это не атака SYN-flood. Проблема SYN-flood атак для средств защиты заключается в большом объеме. Максимальная величина L3&4 составляла 1,5-2 Тбит/с. Такой трафик очень сложно обработать даже крупным компаниям, включая Oracle и Google. SYN и SYN-ACK — это пакеты, которые используются при установке соединения. Поэтому SYN-flood и сложно отличить от легитимной нагрузки: непонятно, это SYN, который пришел на установку соединения, или часть флуда. UDP-flood Обычно у злоумышленников нет тех мощностей, которые есть у нас, поэтому для организации атак может использоваться амплификация. То есть злоумышленник сканирует интернет и находит либо уязвимые, либо неправильно настроенные серверы, которые, например, в ответ на один SYN-пакет, отвечают тремя SYN-ACK. Подделывая адрес источника с адреса целевого сервера, можно с помощью одного пакета увеличить мощность, скажем, в три раза, и перенаправить трафик на жертву. Проблема амплификаций заключается в их сложном обнаружении. Из последних примеров можно привести нашумевший случай с уязвимым memcached. Плюс, сейчас появилось множество устройств IoT, IP-камер, которые тоже в основном настроены по дефолту, и по дефолту они настроены неправильно, поэтому через такие устройства злоумышленники и делают атаки чаще всего. Непростой SYN-flood SYN-flood, наверное, самый интересный вид из всех атак с точки зрения разработчика. Проблема в том, что зачастую системные администраторы используют для защиты блокировку по IP. Причем блокировкой по IP страдают не только сисадмины, которые действуют по скриптам, но и, к сожалению, некоторые системы защиты, которые покупаются за большие деньги. Такой метод может обернуться катастрофой, ведь если злоумышленники подменят IP-адреса, то компания заблокирует собственную подсеть. Когда Firewall заблокирует собственный кластер, на выходе будут рушиться внешние взаимодействия, и ресурс сломается. Причем добиться блокировки собственной сети несложно. Если в офисе клиента есть WI-Fi-сеть, или если работоспособность ресурсов измеряется с помощью различных мониторингов, то мы берем IP-адрес этой системы мониторинга или офисного Wi-Fi клиента, и используем его в качестве источника. На выходе ресурс вроде бы доступен, но целевые IP-адреса заблокированы. Так, может быть заблокирована Wi-Fi-сеть конференции HighLoad, где презентуется новый продукт компании, — и это влечет определенные бизнес- и экономические издержки. Во время тестирования мы не можем использовать амплификацию через memcached какими-то внешними ресурсами, потому что есть договоренности по подаче трафика только в разрешенные IP-адреса. Соответственно мы используем амплификацию через SYN и SYN-ACK, когда на отправку одного SYN система отвечает двумя-тремя SYN-ACK, и на выходе атака умножается в два-три раза. Инструменты Один из основных инструментов, которым мы пользуемся для нагрузки на уровне L7, — это Yandex-tank. В частности, в качестве пушки используется фантом, плюс есть несколько скриптов для генерации патронов и для анализа результатов. Для анализа сетевого трафика используется Tcpdump, для анализа сервера — Nmap. Для создания нагрузки на уровне L3&4 используется OpenSSL и немного собственной магии с библиотекой DPDK. DPDK — это библиотека от Intel, которая позволяет работать с сетевым интерфейсом, минуя стек Linux, и тем самым повышает эффективность. Естественно, DPDK мы используем не только на уровне L3&4, но и на на уровне L7, потому что она позволяет создавать очень высокий поток нагрузки, в пределах нескольких миллионов запросов в секунду с одной машины. Также мы используем определенные трафик-генераторы и специальные инструменты, которые пишем под специфические тесты. Если вспомнить уязвимость под SSH, то приведенным выше набором она не может быть проэскпулатирована. Если мы атакуем почтовый протокол, то берем почтовые утилиты или просто пишем на них скрипты. Выводы В качестве итогов хотелось бы сказать: Помимо классического нагрузочного тестирования нужно обязательно проводить и стресс-тестирование. У нас есть реальный пример, когда субподрядчик партнера провел только нагрузочное тестирование. Оно показало, что ресурс выдерживает штатную нагрузку. Но затем появилась нештатная нагрузка, посетители сайта стали немного иначе использовать ресурс, — и на выходе субподрядчик лег. Таким образом, искать уязвимости стоит, даже если вы уже защищены от DDoS-атак. Необходимо изолировать одни части системы от других. Если у вас есть поиск, его надо вынести на отдельные машины, то есть даже не в докер. Потому что если откажет поиск или авторизация, то хотя бы что-то продолжит работать. В случае с интернет-магазином пользователи продолжат находить товары по каталогу, переходить с агрегатора, покупать, если они уже авторизованы, или авторизовываться через OAuth2. Не стоит пренебрегать всевозможными облачными сервисами. Используйте CDN не только для оптимизации сетевых задержек, но и как средство защиты от атак на исчерпание канала и просто флуда в статику. Необходимо использовать специализированные сервисы защиты. От L3&4 атак на уровне канала сами вы не защититесь, потому что у вас, скорее всего, просто нет достаточного канала. От L7 атак вы тоже вряд ли отобьетесь, поскольку они бывают очень большими. Плюс, поиск маленьких атак это все-таки прерогатива специальных сервисов, специальных алгоритмов. Регулярно обновляйтесь. Это касается не только ядра, но и SSH daemon, особенно если они у вас открыты наружу. В принципе, обновлять надо вообще все, потому что отслеживать те или иные уязвимости самостоятельно вы вряд ли сможете. Ссылка на нашу статью: https://habr.com/ru/company/variti/blog/448626/
  4. У нас есть разные варианты интеграции нашей защиты, фонбет использует один из вариантов. Vega это отдельный лендинг по услугам защиты игровых серверов.
  5. Рады сообщить что мы убрали ограничение по трафику. Так как ранее у многих наших клиентов была проблема с тем, что в зависимости от настроек сервера, они упирались в ограничение по трафику.
  6. На нашем сайте появилась возможность оставить предзаказ на защиту, если в данный момент в ней нет необходимости. Когда будете заказывать защиту перед стартом, просто сообщите нам email, кторый оставляли на сайте.
  7. Да, такие проекты есть, например, L2Name.ru
  8. С 2018 года фильтруем эти атаки, по этому на много больше чем пару раз.
  9. Мы считаем трафик по 95-му перцентилю, что бы не учитывать пиковые нагрузки. По нашей статистике 1 игрок ~ 20кб, но это индивидуально по каждой сборке. Удачно отбиваем данные атаки с 2018 года Гарантируем 100% возврат стоимости, если что-то пойдет не так.
  10. Уважаемые пользователи форума, хотим представить вам проект vega-protect.ru Это отдельное направление от опытного игрока на рынке Variti.com Специализация проекта: защита игровых серверов Lineage 2 от DDoS-атак Помимо этого мы успешно работаем с другими игровыми платформами (Minecraft, RF Online). Чтобы проверить совместимость вашего сервера - напишите нам: vega-protect.ru/#form Проект использует собственную технологию Active Bot Protection. Изучить ее преимущества и сравнить с традиционными методами защиты вы можете на сайте: variti.com/ru-ru/innovations Под нашей защитой работают топовые банки, СМИ, магазины и интернет-сервисы. Больше о наших клиентах: variti.com Мы знаем насколько важна защита именно на старте работы игрового сервера. Поэтому разработали удобные тарифы от 7 дней. Стоимость защиты на 1 месяц и более для каждого проекта рассчитывается индивидуально. Гарантируем 100% возврат стоимости, если что-то пойдет не так. Поддержка наших клиентов по техническим вопросам ведется в Telegram-чате круглосуточно. Будем рады ответить на ваши вопросы! Обращайтесь через форму на сайте: Vega-protect.ru По телефону: 8 800 700 55 39 +7 495 792 22 74 Или пишите на почту vega@variti.com
×
×
  • Создать...