Защита от DDoS на уровне веб-сервера

    Статистика DDoS-атак показывает неизменный рост и смещение вектора с сетевого уровня на уровень приложений.

    image

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

    Первое, что можно и нужно сделать для защиты сайта — настроить брандмауэр iptables. Я использую почти без изменений настройки iptables из статьи на сайте одного из поставщиков защиты от DDoS-атак. Единственное что я поменял — увеличил число допустимых соединений в правилах #8 и #10.

    Прежде чем запускать на выполнение скрипт, меняющий параметры iptables, нужно убедиться, что есть альтернативная возможность сбросить эти параметры в начальное состояние. Т.к. если правила заданы неверно, к серверу не сможет подключится никто, в том числе и администратор.

    Брандмауэр iptables контролирует атаку на сетевом уровне. Следующее что необходимо настроить — это веб-сервер. В качестве веб-сервера, который открыт для доступа из интернет будем рассматривать nginx. В файле nginx.conf нужно увеличить лимиты на колчество файлов и открытых коннектов (пример взят из Википедии):

     # Увеличение максимального количества используемых файлов
      worker_rlimit_nofile 80000;
      events {
          # Увеличение максимального количества соединений
          worker_connections 65536;
          # Использование эффективного метода epoll для обработки соединений
          ...
      }
    

    Далее настраиваем сервер по умолчанию, который будет запрещать доступ для тех устройств (например IoT), который будут обращаться по IP-адресу а не по доменному имени:

    # Default server configuration
    #
    server {
        listen 80 default_server;
        listen 443 ssl default_server;
        deny  all;
    }
    

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

    Чтобы не пересказывать уже имеющийся на Хабре материал, предлагаю ознакомится с отличной статьей, а так же с модулем автора указаной статьи kyprizel/testcookie-nginx-module. То, что позволяет сделать этот модуль уже хорошо. Но если Вам понадобится модернизировать его — то сделать это будет непросто.

    На сегодняшний день очень многие поставщики услуг защиты от DDoS используют сервер openresty (связка nginx + Lua от Taobao). Скорость выполнения хорошего кода на Lua немного уступает хорошему коду на С. Но разрабатывать на Lua быстрее и проще, и к тому же скрипты можно менять без перекомпиляции сервера. При следуюшем рестарте они будут прочитаны, скомпилированы LuaJIT, и это все что требуется.

    Подробная инструкция как уcтановить optnresty. После установки продолжаем настраивать nginx. В разделе http определяем нужные параметры для работы скритов Lua:

    lua_shared_dict whitelist 10m;
    lua_shared_dict banlist 100m;
    
    lua_package_path '/home/username/antiddos/?.lua;;';
    
    init_by_lua '
        local whitelist = ngx.shared.whitelist
        whitelist:add("1.2.3.4", true)
        whitelist:add("5.6.7.8", true)
    ';
    
    access_by_lua_file /home/username/antiddos/main.lua;
    

    Строка lua_shared_dict создает новый словарь (ключ-значение). Этот словарь будет единым для всех запросов, поэтому в нем удобно хранить белые и черные списки. Это словарь, кроме параметров ключ-значение, может иметь параметр time-to-live, который идеально подходит для хранения счетчиков, если нужно ограничить количество запросов в промежуток времени.

    Строка lua_package_path задает пути для поиска модулей Lua, в котрый нужно включить каталог со скриптами. Две подряд точки с запятой в конце строки означают, что этот путь добавляется к текущему значению пути, а не полностью заменяет его.

    Строка init_by_lua задает код, который будет выполнен один раз при старте сервера (а не при каждом новом запросе). В ней задается белый список IP-адресов. Второй праметр функции add — true — это просто значние которое потом используется в операторе if. Третий параметр time-to-live отсутсвует, поэтому значение будет храниться без ограничения по времени.

    Строка access_by_lua_file задает путь к скрипту, который будет выполняться при каждом запросе к серверу (не только при старте сервера). В нем, собственно, и находится вся логика защиты.

    Рассмотрим некоторые из проверок, которые можно сделать при помощи скрипта на Lua:

    -- if client IP is in whitelist, pass
    local whitelist = ngx.shared.whitelist
    in_whitelist = whitelist:get(ngx.var.remote_addr)
    if in_whitelist then
        return
    end
    
    -- HTTP headers
    local headers = ngx.req.get_headers();
    
    -- wp ddos
    if type(headers["User-Agent"]) ~= "string"
        or headers["User-Agent"] == ""
        or ngx.re.find(headers["User-Agent"], "^WordPress", "ioj") then
        ngx.log(ngx.ERR, "ddos")
        ngx.exit(444)
        return
    end
    
    local banlist = ngx.shared.banlist
    local search_bot = "search:bot:count:request:per:10:s"
    if ngx.re.find(headers["User-Agent"], "Google Page Speed Insights|Googlebot|baiduspider|twitterbot|facebookexternalhit|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator", "ioj") then
       local count, err = banlist:incr(search_bot, 1)
        if not count then
            banlist:set(search_bot, 1, 10)
            count = 1
        end
        if count >= 50 then
            if count == 50 then
                ngx.log(ngx.ERR, "bot banned")
            end
            ngx.exit(444)
            return
        end
        return
    end
    

    Язык Lua во многом похож (даже слишком) на JavaScript, поэтому код на Lua интуитивно понятен всем, кто пишет на JavaScript.

    Глобальная переменная ngx служит для связи с контекстом сервера nginx. Оператор return вне тела функции означает возврат из модуля. В данном примере, если IP-адрес в белом списке, то работа скрипта оканчивается, и продолжается обычная обработка запроса nginx.

    Далее распознается атака, основанная на особенностей реализации CMS WordPress. Если атака выявлена то работа оканчивается специальным статусом 444 (характерен только для nginx): ngx.exit(444).

    И, наконец, мы даем «зеленую дорогу» поисковым ботам. Тут приходится использовать счетчик, т.к. под поискового бота часто подделываются злоумышленники — поэтому считаем количество обращений. banlist:set(search_bot, 1, 10) инициализирует счетчик, который обнулится через 10 секунд после создания. banlist:incr(search_bot, 1) прибавляет к текущему значению счетчика единицу.

    Дальнейшее распознавание ботов и злоумышленников может вестись по разным направлениям. Как было предложено в статье такое распознавание основано на проверках, поддерживает ли клиент редиректы, установку cookie и выполнения кода JavaScript. Ну или все, что можно еще придумать.

    Как правило, такой веб-сервер используют в качестве прокси, а защищаемый веб-сервер размещают на другом IP-адресе.

    apapacy@gmail.com
    22 января 2018 года.
    • +22
    • 12,5k
    • 4
    Поделиться публикацией
    Похожие публикации
    Ммм, длинные выходные!
    Самое время просмотреть заказы на Фрилансим.
    Мне повезёт!
    Реклама
    Комментарии 4
    • 0
      Вот неплохо бы понимать что опции по ссылке делают.
      • 0
        В статье по ссылке есть минимально необходимые пояснения. Плюс документация iptables. Некоторые правила требуют ещё и хорошего понимания сетевых протоколов. Я их тоже не до конца все понимаю. Поэтому привёл ссылку на статью из надежного источника. Я их использую в рабочем окружении с указанными изменениями. Правила без защиты на уровне веб-сервера не защищают от атак на высокие уровни т.к. приложение валится от исчерпания ресурсов памяти и процессора задолго до исчерпания ресурсов сети. Поэтому статью опубликовала фирма которая делает бизнес на защите не боясь потерять клиентов
      • 0
        Хорошая, статья.
        Применю (попробую) на практике рекомендации, посмотрим что получится…
        • +1
          Windows 98 без антивирусника. Сейчас просто вирусы уже на ней не запускаются. Нормально работают компьютеры.

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.