• Обратная связь:[email protected]

    Наш канал в telegram:https://t.me/ru_sfera

    Пользователи могут писать на форуме ТОЛЬКО ЧЕРЕЗ 7 ДНЕЙ после регистрации

Программа ИБ Интеллектуальный скрипт для защиты от ддос на L7


X-Shar

:)
Администрация
Регистрация
03.06.2012
Сообщения
6 229
Репутация
8 358
1736961407332.png


Всем привет!

Для начала краткая теория-шпаргалка:

Какие бывают DDoS атаки?

По типу объекта, который выводится из строя можно выделить четыре основных класса атак, осуществляемых на разных уровнях согласно модели OSI:

Первый класс (L2) — «забивание» канала. Эти атаки направлены на лишение доступа сервера к внешней сети вследствие исчерпания ширины его канала. Чаще всего в таких случаях используются массированные, с точки зрения количества трафика, атаки типа Amplification (NTP-, DNS-, RIP-… Amplification может быть любой). Основная задача состоит в том, чтобы канал шириной, например, 1 гигабит/с залить хотя бы 1,1 гигабит/с. Этого будет достаточно для прекращения доступа к серверу.

К данному классу атак также относятся различные flood’ы:
  • SYN-флуд (TCP/SYN) устанавливает полуоткрытые соединения с узлом. Когда жертва принимает SYN-пакет через открытый порт, она должна послать в ответ SYN-ACK пакет и установить соединение. После этого инициатор посылает получателю ответ с ACK-пакетом. Данный процесс условно называется рукопожатием. Однако, во время атаки SYN-флудом рукопожатие не может быть завершено, т.к. злоумышленник не отвечает на SYN-ACK сервера-жертвы. Такие соединения остаются полуоткрытыми до истечения тайм-аута, очередь на подключение переполняется и новые клиенты не могут подключиться к серверу
  • UDP-флуд чаще всего используются для широкополосных DDoS-атак в силу их бессеансовости, а также простоты создания сообщений протокола 17 (UDP) различными языками программирования.
  • ICMP-флуд. Протокол межсетевых управляющих сообщений (ICMP) используется в первую очередь для передачи сообщений об ошибках и не используется для передачи данных. ICMP-пакеты могут сопровождать TCP-пакеты при соединении с сервером.
Второй класс (L3) — нарушение функционирования сетевой инфраструктуры. К этому классу относятся, в числе прочего, атаки, приводящие к проблемам с маршрутизацией в рамках протокола BGP, с анонсами сетей (Hijacking) — или атаки, следствием которых становятся проблемы на транзитном сетевом оборудовании: например, переполнение таблицы отслеживания соединений. Атаки данного класса отличаются большим разнообразием.

Третий класс (L4) — эксплуатация слабых мест TCP-стека, то есть атаки на транспортном уровне. Этот транспортный протокол, лежащий в основе HTTP и ряда других протоколов, довольно сложно устроен. Например, в нём используется большая таблица открытых соединений, каждое из которых является, фактически, конечным автоматом. И именно атаки на этот автомат составляют третий класс DDoS-нападений.

Четвёртый класс (L7) — деградация Web-приложения. Сюда относятся всевозможные «кастомные» атаки, начиная от типичного GET/POST/HTTP Flood до нападений, нацеленных на многократно повторяющиеся поиск и извлечение конкретной информации из БД, памяти или с диска, пока у сервера просто не закончатся ресурсы.

Если отражение атак класса L2-L4 это прерогатива хостинга обычно, достаточно заказать сервер с защитой от ддос, также от таких атак спасают облачные сервисы такие как CloudFlare, DDOSGUARD и т.д.

А вот с атаками уровня приложения, тут проблема, очень тяжело фильтровать такой трафик, ведь система защиты ничего незнает, как фильтровать что-бы не поафектить ваш сайт.
К сожалению тот-же CloudFlare даже на платных тарифах не защищает от таких типов атак.

Да, можно сделать режим "Я под атакой", который будет постоянно проверять HTTP трафик, показывая посетителям капчу, но тогда перестанут работать различные API вашего сайта, мониторинги и т.д. + посетителям не всегда приятно лицезреть капчу.

Короче постоянно держать капчу не вариант.

На дорогих тарифах появилась интелектуальная фильтрация, но стоит такая защита нет менее 200$, да и тоже пропучкает...:(

Поэтому предлагаю разработать мониторинг, который будет ну скажем раз в 10 секунд мониторить нашу систему (Такие метрики как загрузка CPU и число соединений веб-сервера) и в случае обнаружения аномалий включать защиту, я взял CloudFlare и её API, т.к. это можно сделать на бесплатном тарифе.

Наш скрипт должен запускать с максимальным приоритетом nice -n -10, далее в бесконечном цикле раз в 10 секунд делать метрики.

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

Вот примерная схема работы:


Код:
                ┌─────────────────────┐
                │      Сервер        │
                │ (Nginx + система)  │
                └─────────┬──────────┘
                          │
             (1) Сбор метрик (CPU, Nginx)
                          │
                          v
     ┌───────────────────────────────┐
     │  Скрипт cloudflare_load_monitor.sh  │
     │    (мониторинг + логика включения   │
     │      "Я под атакой" в Cloudflare)   │
     └─────────────────┬───────────────────┘
                       │
         (2) Проверка порогов CPU/Conn
                       │
                       │  Порог превышен?
                       │
         ┌────── Нет ──┴───────────────────┐
         │                                 │
         │Да                                v
         v                       (3) Включаем under_attack
 ┌─────────────────┐                 через Cloudflare API
 │  Скрипт ждёт    │─────────────────────────────────────────┐
 │  ATTACK_DURATION│                                         │
 └─────────────────┘                                         │
                      (4) По истечении времени               │
                             переводим режим обратно         │
                                 в DEFAULT_SECURITY_LEVEL     │
                                                              │
                                                              v
                                   ┌─────────────────────────┐
         (5) Отправка email  ─────▶│   Уведомления на почту  │
          (начало/конец атак)      └─────────────────────────┘

Объяснение схемы​

  1. Сервер (Nginx + система):
    • Здесь работают веб-сервер Nginx и система, где проверяется загрузка CPU.
  2. (1) Сбор метрик:
    • Скрипт обращается к mpstat для чтения % загрузки CPU.
    • Делаает запрос к , чтобы узнать число активных соединений (Active connections).
  3. (2) Проверка порогов:
    • Скрипт сверяет полученные значения (CPU и Conn) с заданными порогами (CPU_THRESHOLD и CONN_THRESHOLD).
  4. (3) Включение режима "Я под атакой":
    • Если порог(и) превышены, скрипт делает PATCH-запрос к Cloudflare API, переводя уровень безопасности в under_attack.
  5. (4) Ожидание ATTACK_DURATION:
    • Скрипт удерживает режим "Я под атакой" заданное время (например, 300 секунд), периодически проверяя, не нужно ли завершить работу (файл /tmp/cloudflare_monitor_stop).
  6. (5) Возврат в DEFAULT_SECURITY_LEVEL + уведомление:
    • По завершении периода ожидания скрипт возвращает Cloudflare в стандартный режим (например, medium) и рассылает email-уведомление об окончании режима «Я под атакой».

Итак начнем разработку:​

Шаг 1. Подготовка окружения​

1. Установка необходимых пакетов​

  1. sysstat – для утилиты mpstat, которая нужна для мониторинга CPU.
  2. mailutils (или mailx) – для отправки email-уведомлений.
  3. bc – в некоторых системах требуется для арифметических операций (echo "100 - idle" | bc -l).
  4. jq – для форматирования и обработки JSON-ответов от Cloudflare (не обязательно, но полезно).
Примеры установки для Ubuntu/Debian:

Код:
sudo apt update
sudo apt install -y sysstat mailutils bc jq

Для CentOS/RHEL:

Код:
sudo yum install -y sysstat mailx bc jq

2. Настройка Nginx для получения метрик​

Чтобы скрипт мог подсчитывать число активных соединений, нужно включить ngx_http_stub_status_module. Обычно он собран по умолчанию, достаточно задать соответствующий location.

Пример добавления локейшена в конфигурацию Nginx (файл /etc/nginx/conf.d/status.conf (Нужно создать файл с содержимым ниже) или nginx.conf):

Код:
server {
    listen 127.0.0.1:80;
    server_name localhost;

    location /nginx_status {
        stub_status;        # Включаем модуль
        allow 127.0.0.1;    # Разрешаем доступ только с localhost
        deny all;           # Остальным запрещаем
    }
}

Затем перезагрузите Nginx:
Код:
sudo systemctl reload nginx

Теперь метрика будет доступна по адресу .

Шаг 2. Получение Cloudflare API Token​

  1. Зайдите в свою учётную запись на
  2. Нажмите Create Custom Token.
  3. Укажите необходимые Permissions:
    • Zone: Zone Settings: Edit
  4. Выберите нужные Zone Resources:
    • Include > Specific zone (или All zones, если нужно для всех доменов).
  5. Сохраните настройки и создайте токен.
  6. Скопируйте полученный токен и сохраните в безопасном месте (после создания полностью скопировать его можно будет только один раз!).
  7. Таже нужен будет Account ID вашего домена, его можно увидеть в правой панели тут на вкладке Overview.

Шаг 3. Создание скрипта мониторинга​

Ниже приведён пример bash-скрипта, который:
  • Мониторит загрузку CPU (через mpstat) и число активных соединений (через Nginx stub_status).
  • Если превышен порог по загрузке CPU или по числу активных соединений, переводит Cloudflare в режим «Я под атакой» на 5 минут (300 секунд).
  • Отправляет email-уведомления при входе в режим атаки и при возврате в нормальный режим.
  • Ведёт лог в файл /var/log/cloudflare_load_monitor.log.
  • Завершается, если обнаружит файл /tmp/cloudflare_monitor_stop.
Сохраните его, например, в /opt/scripts/cloudflare_load_monitor.sh (не забудьте выдать права на исполнение: chmod +x /opt/scripts/cloudflare_load_monitor.sh).

Bash:
#!/bin/bash
# cloudflare_load_monitor.sh
#
# Скрипт мониторинга CPU и активных соединений Nginx. При превышении порогов
# включается режим "Я под атакой" в Cloudflare, затем через 5 минут
# режим возвращается в исходный.

export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

#### Настройки Cloudflare ####
CF_API_TOKEN="ВСТАВЬТЕ_СВОЙ_API_TOKEN"
ZONE_ID="ВСТАВЬТЕ_СВОЙ_ZONE_ID"
DEFAULT_SECURITY_LEVEL="medium"
SECURITY_LEVEL_ATTACK="under_attack"

#### Настройки мониторинга ####
CPU_THRESHOLD=90                  # Порог CPU (в %)
CONN_THRESHOLD=2000               # Порог активных соединений Nginx
CHECK_INTERVAL=10                 # Интервал проверки (сек)
ATTACK_DURATION=300               # Длительность режима "Я под атакой" (сек)
NGINX_STATUS_URL="http://127.0.0.1/nginx_status"

#### Настройки уведомлений ####
EMAIL_TO="[email protected]"      # Куда отправлять уведомления

#### Логирование ####
LOG_FILE="/var/log/cloudflare_load_monitor.log"

# Функция логирования
log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') $1" | tee -a "$LOG_FILE" >&2
}

# Функция отправки email
send_email() {
    local subject="$1"
    local message="$2"
    echo "$message" | mail -s "$subject" "$EMAIL_TO"
}

# Установка security_level в Cloudflare
set_cf_security_level() {
    local level="$1"
    log "Меняем режим безопасности Cloudflare на: ${level}"
    response=$(curl -s -X PATCH "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/settings/security_level" \
         -H "Authorization: Bearer ${CF_API_TOKEN}" \
         -H "Content-Type: application/json" \
         --data "{\"value\":\"${level}\"}")
    log "Ответ Cloudflare: $response"
}

# Получение загрузки CPU
get_cpu_usage() {
    local idle
    idle=$(LANG=C mpstat 1 1 | awk '/Average/ {print $(NF)}')
    if [ -z "$idle" ]; then
        echo 0
    else
        printf "%.0f" "$(echo "100 - $idle" | bc -l)"
    fi
}

# Function to get the number of active Nginx connections.
# Assumes that Nginx is configured with ngx_http_stub_status_module.
# If the status page is unavailable (e.g. due to exhausted worker_connections),
# the function returns CONN_THRESHOLD+1 to trigger protection.
get_nginx_conn() {
    local status
    status=$(curl -s "$NGINX_STATUS_URL")
    if [ -z "$status" ] || [[ "$status" != *"Active connections:"* ]]; then
        log "Unable to retrieve Nginx status. Possibly worker_connections are exhausted."
        echo $((CONN_THRESHOLD + 1))
    else
        echo "$status" | awk '/Active connections/ {print $3}'
    fi
}

# Проверка наличия необходимых утилит
if ! command -v mpstat >/dev/null 2>&1; then
    log "mpstat не найден. Установите пакет sysstat."
    exit 1
fi

if ! command -v mail >/dev/null 2>&1; then
    log "Утилита mail не найдена. Установите пакет mailutils (или mailx)."
    exit 1
fi

log "Запуск скрипта мониторинга Cloudflare. PID: $$"

while true; do
    # Если обнаружен /tmp/cloudflare_monitor_stop — завершаемся
    if [ -f /tmp/cloudflare_monitor_stop ]; then
        log "Найден /tmp/cloudflare_monitor_stop, завершаем работу."
        rm -f /tmp/cloudflare_monitor_stop
        exit 0
    fi

    CPU_USAGE=$(get_cpu_usage)
    NGINX_CONN=$(get_nginx_conn)

    log "Текущая загрузка CPU: ${CPU_USAGE}%"
    log "Текущее число активных соединений: ${NGINX_CONN}"

    TRIGGER_CPU=0
    TRIGGER_CONN=0

    [ "$CPU_USAGE" -gt "$CPU_THRESHOLD" ] && TRIGGER_CPU=1
    # Если NGINX_CONN — это число и оно больше заданного порога
    if [[ "$NGINX_CONN" =~ ^[0-9]+$ ]] && [ "$NGINX_CONN" -gt "$CONN_THRESHOLD" ]; then
        TRIGGER_CONN=1
    fi

    if [ "$TRIGGER_CPU" -eq 1 ] || [ "$TRIGGER_CONN" -eq 1 ]; then
        REASON=""
        [ "$TRIGGER_CPU" -eq 1 ] && REASON+="CPU usage выше порога (${CPU_USAGE}%). "
        [ "$TRIGGER_CONN" -eq 1 ] && REASON+="Число соединений выше порога (${NGINX_CONN})."

        log "Обнаружены условия перегрузки: $REASON"
        send_email "Включение режима 'Я под атакой'" "Включён режим 'under_attack' в Cloudflare. Причина: $REASON"

        set_cf_security_level "$SECURITY_LEVEL_ATTACK"

        log "Удерживаем режим '${SECURITY_LEVEL_ATTACK}' в течение ${ATTACK_DURATION} секунд..."
        SECONDS_PASSED=0
        while [ $SECONDS_PASSED -lt $ATTACK_DURATION ]; do
            sleep 10
            SECONDS_PASSED=$((SECONDS_PASSED+10))
            if [ -f /tmp/cloudflare_monitor_stop ]; then
                log "Файл /tmp/cloudflare_monitor_stop найден во время режима атаки, завершаем работу."
                exit 0
            fi
        done

        log "Возвращаем режим безопасности на '${DEFAULT_SECURITY_LEVEL}'"
        set_cf_security_level "$DEFAULT_SECURITY_LEVEL"
        send_email "Возврат нормального режима" "Снятие режима 'under_attack'. Возврат к '${DEFAULT_SECURITY_LEVEL}'."
    fi

    sleep "$CHECK_INTERVAL"
done

Важны эти настройки:

Код:
#### Настройки Cloudflare ####
CF_API_TOKEN="ВСТАВЬТЕ_СВОЙ_API_TOKEN"
ZONE_ID="ВСТАВЬТЕ_СВОЙ_ZONE_ID"
DEFAULT_SECURITY_LEVEL="medium"
SECURITY_LEVEL_ATTACK="under_attack"

#### Настройки мониторинга ####

CPU_THRESHOLD=90                  # Порог CPU (в %)
CONN_THRESHOLD=2000               # Порог активных соединений Nginx
CHECK_INTERVAL=10                 # Интервал проверки (сек)
ATTACK_DURATION=300               # Длительность режима "Я под атакой" (сек)

NGINX_STATUS_URL="http://127.0.0.1/nginx_status"

Укажите свои настройки, например CONN_THRESHOLD=2000 # Порог активных соединений Nginx, я указал такой, т.к. у меня в конфиге:

worker_processes 3; worker_connections 768 итого максимально может-быть 2 304 коннектов, сделал немного меньше для мониторинга, также и CPU_THRESHOLD=90.

Шаг 4. Создание скрипта контроля мониторинга​

Нам важно что-бы скрипт мониторинга всегда работал, даже после крашей, для этого сделаем мониторинг нашего мониторинга.)
Который будет проверять что наш скрипт мониторинга запущен и в случае чего перезапускать его.

Bash:
#!/bin/bash
# monitor_cloudflare_monitor.sh
#
# Этот скрипт проверяет, запущен ли основной скрипт мониторинга (cloudflare_load_monitor.sh).
# Если монитор не запущен, он запускает его с повышенным приоритетом и логирует событие.

export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

LOG_FILE="/var/log/cloudflare_monitor_supervisor.log"
MONITOR_SCRIPT="/var/local/cloudflare_load_monitor.sh"

# Функция логирования
log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') $1" | tee -a "$LOG_FILE"
}

# Имя процесса: можно искать по имени скрипта
PROCESS_COUNT=$(pgrep -fc "$(basename "$MONITOR_SCRIPT")")

if [ "$PROCESS_COUNT" -eq 0 ]; then
    log "Основной скрипт мониторинга не найден. Запускаем его с повышенным приоритетом."
    # Запускаем с повышенным приоритетом. Здесь используется nice с значением -10.
    # Запускаем в фоне и перенаправляем вывод в лог.
    nohup nice -n -10 "$MONITOR_SCRIPT" >/dev/null 2>&1 &
    sleep 5  # Подождем немного, чтобы процесс стартовал.
    log "Скрипт мониторинга запущен. PID: $!"
else
    log "Скрипт мониторинга уже запущен (процессов: ${PROCESS_COUNT})."
fi

И добавим его в крон (Prio -10), проверять раз в минуту (Не забудьте установить права на исполнение скрипта):

Код:
crontab -e
* * * * * /usr/bin/nice -n -10 /bin/bash /var/local/monitor_cloudflare_monitor.sh

Да и все скрипты надо выполнять с правами рута.

Шаг 5. Настройка ротации логов​

Чтобы лог-файл /var/log/cloudflare_load_monitor.log не разрастался бесконечно, нужно настроить ротацию через logrotate.

Создайте файл /etc/logrotate.d/cloudflare_load_monitor со следующим содержимым:

Код:
/var/log/cloudflare_load_monitor.log {
    daily
    rotate 7
    compress
    missingok
    notifempty
    create 644 root root
    sharedscripts
    postrotate
    endscript
}

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

Итог​

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

Статья на английском языке в моем гитхабе:
 
Последнее редактирование:

X-Shar

:)
Администрация
Регистрация
03.06.2012
Сообщения
6 229
Репутация
8 358
Статья на английском языке в моем гитхабе:
 

X-Shar

:)
Администрация
Регистрация
03.06.2012
Сообщения
6 229
Репутация
8 358

X-Shar

:)
Администрация
Регистрация
03.06.2012
Сообщения
6 229
Репутация
8 358
Можно ещё модифицировать:

Проверка раз в 10 секунд, но если обнаруживается, что: - CPU usage > CPU_THRESHOLD 5 раз подряд, то включается защита.

Это более мягкий фильтр, от ложных срабатываний.)

Bash:
#!/bin/bash
# cloudflare_load_monitor.sh
#
# This script monitors the CPU load and the number of active Nginx connections.
# If it detects that:
#   - CPU usage > CPU_THRESHOLD 5 times in a row, or
#   - the number of active connections > CONN_THRESHOLD (just once),
# then Cloudflare is switched to "under_attack" mode for ATTACK_DURATION seconds,
# and an email notification is sent with the reason for the switch.
#
# To stop this script, create the file /tmp/cloudflare_monitor_stop.

export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

#### Cloudflare Settings ####
CF_API_TOKEN="INSERT_YOUR_API_TOKEN"
ZONE_ID="INSERT_YOUR_ZONE_ID"
DEFAULT_SECURITY_LEVEL="medium"     # default mode
SECURITY_LEVEL_ATTACK="under_attack"

#### Monitoring Settings ####
CPU_THRESHOLD=80                    # CPU threshold (in %)
CONN_THRESHOLD=2000                 # Nginx connection threshold
CHECK_INTERVAL=10                   # check interval (seconds)
ATTACK_DURATION=300                 # "under_attack" mode duration (seconds)
NGINX_STATUS_URL="http://127.0.0.1/nginx_status"  # URL to retrieve Nginx status

#### Notification Settings ####
EMAIL_TO="notification@mail"         # email for notifications

#### Logging ####
LOG_FILE="/var/log/cloudflare_load_monitor.log"

# Logging function: output to log file and console
log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') $1" | tee -a "$LOG_FILE" >&2
}

# Email sending function
send_email() {
    local subject="$1"
    local message="$2"
    echo "$message" | mail -s "$subject" "$EMAIL_TO"
}

# Function to set security_level via the Cloudflare API
set_cf_security_level() {
    local level="$1"
    log "Changing Cloudflare security mode to: ${level}"
    response=$(curl -s -X PATCH "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/settings/security_level" \
         -H "Authorization: Bearer ${CF_API_TOKEN}" \
         -H "Content-Type: application/json" \
         --data "{\"value\":\"${level}\"}")
    log "Cloudflare response: $response"
}

# Function to get CPU usage using mpstat
get_cpu_usage() {
    local idle
    # Force LANG=C so mpstat will print "Average"
    idle=$(LANG=C mpstat 1 1 | awk '/Average/ {print $(NF)}')
    if [ -z "$idle" ]; then
        echo 0
    else
        # Calculate usage as 100 - idle (rounded)
        printf "%.0f" "$(echo "100 - $idle" | bc -l)"
    fi
}

# Function to get the number of active Nginx connections.
# Assumes that Nginx is configured with ngx_http_stub_status_module.
# If the status page is unavailable (e.g. due to exhausted worker_connections),
# the function returns CONN_THRESHOLD+1 to trigger protection.
get_nginx_conn() {
    local status
    status=$(curl -s "$NGINX_STATUS_URL")
    if [ -z "$status" ] || [[ "$status" != *"Active connections:"* ]]; then
        log "Unable to retrieve Nginx status. Possibly worker_connections are exhausted."
        echo $((CONN_THRESHOLD + 1))
    else
        echo "$status" | awk '/Active connections/ {print $3}'
    fi
}

# Check required commands
if ! command -v mpstat >/dev/null 2>&1; then
    log "mpstat not found. Please install the sysstat package."
    exit 1
fi

if ! command -v jq >/dev/null 2>&1; then
    log "jq not found. Please install the jq package."
    exit 1
fi

if ! command -v mail >/dev/null 2>&1; then
    log "mail command not found. Please install the mailutils (or mailx) package to send notifications."
    exit 1
fi

log "Starting Cloudflare monitoring script. PID: $$"

# Counter for consecutive CPU threshold exceedances
CPU_EXCEED_COUNT=0

# Main monitoring loop
while true; do
    # If the stop file exists, terminate
    if [ -f /tmp/cloudflare_monitor_stop ]; then
        log "Detected /tmp/cloudflare_monitor_stop. Stopping the script."
        rm -f /tmp/cloudflare_monitor_stop
        exit 0
    fi

    # Get current metrics:
    CPU_USAGE=$(get_cpu_usage)
    NGINX_CONN=$(get_nginx_conn)
    log "Current CPU load: ${CPU_USAGE}%"
    log "Current number of active Nginx connections: ${NGINX_CONN}"

    # Reset trigger flags
    TRIGGER_CPU=0
    TRIGGER_CONN=0

    # CPU logic: increment counter if threshold is exceeded, otherwise reset
    if [ "$CPU_USAGE" -gt "$CPU_THRESHOLD" ]; then
        CPU_EXCEED_COUNT=$((CPU_EXCEED_COUNT+1))
        log "CPU threshold exceeded. CPU_EXCEED_COUNT = ${CPU_EXCEED_COUNT}"
        # If threshold exceeded 5 times in a row, set TRIGGER_CPU
        if [ "$CPU_EXCEED_COUNT" -ge 5 ]; then
            TRIGGER_CPU=1
            # Reset counter after triggering
            CPU_EXCEED_COUNT=0
        fi
    else
        CPU_EXCEED_COUNT=0
    fi

    # If NGINX_CONN is not a number, consider the condition as not met
    if [[ "$NGINX_CONN" =~ ^[0-9]+$ ]] && [ "$NGINX_CONN" -gt "$CONN_THRESHOLD" ]; then
        TRIGGER_CONN=1
    fi

    # Check if we need to switch to "under_attack" mode
    if [ "$TRIGGER_CPU" -eq 1 ] || [ "$TRIGGER_CONN" -eq 1 ]; then
        REASON=""
        if [ "$TRIGGER_CPU" -eq 1 ]; then
            REASON+="CPU usage exceeded (over ${CPU_THRESHOLD}% 5 times in a row). "
        fi
        if [ "$TRIGGER_CONN" -eq 1 ]; then
            REASON+="Nginx connections exceeded (${NGINX_CONN} > ${CONN_THRESHOLD})."
        fi
        log "Overload conditions detected: $REASON"
    
        # If switching to under_attack mode, send email
        send_email "Enabling 'under_attack' mode" "Switching Cloudflare to 'under_attack' mode due to: $REASON"

        # Switch to under_attack mode
        set_cf_security_level "$SECURITY_LEVEL_ATTACK"

        log "Holding '${SECURITY_LEVEL_ATTACK}' mode for ${ATTACK_DURATION} seconds."
        # Wait in a loop, checking every 10 seconds (stop file can still stop it)
        SECONDS_PASSED=0
        while [ $SECONDS_PASSED -lt $ATTACK_DURATION ]; do
            sleep 10
            SECONDS_PASSED=$((SECONDS_PASSED+10))
            if [ -f /tmp/cloudflare_monitor_stop ]; then
                log "Detected /tmp/cloudflare_monitor_stop during attack mode. Stopping."
                rm -f /tmp/cloudflare_monitor_stop
                exit 0
            fi
        done

        log "Reverting Cloudflare security mode back to '${DEFAULT_SECURITY_LEVEL}'"
        set_cf_security_level "$DEFAULT_SECURITY_LEVEL"
        send_email "Reverting to normal mode" "Reverted to '${DEFAULT_SECURITY_LEVEL}' mode after disabling 'under_attack'."
    fi

    sleep "$CHECK_INTERVAL"
done
 
Последнее редактирование:

X-Shar

:)
Администрация
Регистрация
03.06.2012
Сообщения
6 229
Репутация
8 358
Полезные темы также:




 

X-Shar

:)
Администрация
Регистрация
03.06.2012
Сообщения
6 229
Репутация
8 358
Можно ещё модифицировать.

Добавить проверку коннектов апаче, например если у вас nginx + apache.

Проверяет число коннектов к апаче, в примере 100 коннектов лимит включения защиты.

Bash:
#!/bin/bash
# cloudflare_load_monitor.sh
#
# This script monitors:
#   1) CPU usage,
#   2) The number of active Nginx connections (via ngx_http_stub_status),
#   3) The number of active Apache connections.
#
# If any of the following conditions is met:
#   - CPU usage > CPU_THRESHOLD for 5 consecutive checks, or
#   - The number of Nginx connections > CONN_THRESHOLD (once), or
#   - The number of Apache connections > APACHE_CONN_THRESHOLD (once),
# then Cloudflare is switched into "under_attack" mode for ATTACK_DURATION seconds,
# and email notifications are sent with the reason for the switch.
#
# To stop the script, create the file /tmp/cloudflare_monitor_stop.

export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

#############################################
#### Cloudflare Settings ####################
#############################################
CF_API_TOKEN="Replace_with_your_real_API_token"    # <-- Replace with your real API token
ZONE_ID="Replace_with_your_real_zone_id"            # <-- Replace with your real zone_id
DEFAULT_SECURITY_LEVEL="medium"                     # default security level
SECURITY_LEVEL_ATTACK="under_attack"

#############################################
#### Monitoring Settings ####################
#############################################
CPU_THRESHOLD=80                   # CPU threshold (in %)
CONN_THRESHOLD=2000                # Nginx connections threshold
APACHE_CONN_THRESHOLD=100          # Apache connections threshold
CHECK_INTERVAL=10                  # interval between checks (seconds)
ATTACK_DURATION=300                # duration of "under_attack" mode (seconds)

NGINX_STATUS_URL="http://127.0.0.1/nginx_status"  # URL for retrieving Nginx status (using ngx_http_stub_status)

#############################################
#### Apache Monitoring Settings #############
#############################################
APACHE_PORT=8080                   # Port on which Apache is listening (as defined in your VirtualHost)
APACHE_PROCESS_NAME="apache2"      # Apache process name (for Debian/Ubuntu: apache2, for CentOS/RHEL: httpd)

#############################################
#### Notification Settings ##################
#############################################
EMAIL_TO="[email protected]"        # email address for notifications

#############################################
#### Logging Settings #######################
#############################################
LOG_FILE="/var/log/cloudflare_load_monitor.log"

# Logging function: outputs message to the log file and the console
log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') $1" | tee -a "$LOG_FILE" >&2
}

# Email sending function
send_email() {
    local subject="$1"
    local message="$2"
    echo "$message" | mail -s "$subject" "$EMAIL_TO"
}

# Function to set the Cloudflare security level via API
set_cf_security_level() {
    local level="$1"
    log "Changing Cloudflare security level to: ${level}"
    response=$(curl -s -X PATCH "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/settings/security_level" \
         -H "Authorization: Bearer ${CF_API_TOKEN}" \
         -H "Content-Type: application/json" \
         --data "{\"value\":\"${level}\"}")
    log "Cloudflare response: $response"
}

# Function to get CPU usage using mpstat
get_cpu_usage() {
    local idle
    # Force LANG=C to ensure mpstat outputs "Average"
    idle=$(LANG=C mpstat 1 1 | awk '/Average/ {print $(NF)}')
    if [ -z "$idle" ]; then
        echo 0
    else
        # Calculate CPU usage as 100 - idle (rounded)
        printf "%.0f" "$(echo "100 - $idle" | bc -l)"
    fi
}

# Function to get the number of active Nginx connections.
# Assumes that Nginx is configured with ngx_http_stub_status_module.
# If the status page is unavailable (e.g. due to exhausted worker_connections),
# the function returns CONN_THRESHOLD+1 to trigger protection.
get_nginx_conn() {
    local status
    status=$(curl -s "$NGINX_STATUS_URL")
    if [ -z "$status" ] || [[ "$status" != *"Active connections:"* ]]; then
        log "Unable to retrieve Nginx status. Possibly worker_connections are exhausted."
        echo $((CONN_THRESHOLD + 1))
    else
        echo "$status" | awk '/Active connections/ {print $3}'
    fi
}

# Function to get the number of active Apache connections
get_apache_conn() {
    # Uses ss to count established (ESTAB) connections on the Apache port.
    # Requires that Apache is listening on 127.0.0.1:APACHE_PORT and its processes are named appropriately.
    local port="$APACHE_PORT"
    local process="$APACHE_PROCESS_NAME"

    local conn_count
    conn_count=$(ss -tanp | awk -v port="$port" -v proc="$process" '
        $1=="ESTAB" && $4 ~ ":"port"$" && $0 ~ proc { count++ }
        END { print count+0 }
    ')
    echo "$conn_count"
}

# Check for necessary commands
if ! command -v mpstat >/dev/null 2>&1; then
    log "mpstat not found. Please install the sysstat package."
    exit 1
fi

if ! command -v jq >/dev/null 2>&1; then
    log "jq not found. Please install the jq package."
    exit 1
fi

if ! command -v mail >/dev/null 2>&1; then
    log "The mail utility not found. Please install mailutils (or mailx) for notifications."
    exit 1
fi

# Check availability of the Nginx status page
if ! curl -s "$NGINX_STATUS_URL" | grep -q "Active connections"; then
    log "Unable to retrieve Nginx status. Ensure Nginx is configured with ngx_http_stub_status_module and available at $NGINX_STATUS_URL."
    exit 1
fi

log "Starting Cloudflare load monitoring script. PID: $$"

# Counter for consecutive CPU threshold exceedances
CPU_EXCEED_COUNT=0

# Main monitoring loop
while true; do
    # Stop the script if the stop file is found
    if [ -f /tmp/cloudflare_monitor_stop ]; then
        log "Stop file /tmp/cloudflare_monitor_stop found. Exiting script."
        rm -f /tmp/cloudflare_monitor_stop
        exit 0
    fi

    # Get current metrics
    CPU_USAGE=$(get_cpu_usage)
    NGINX_CONN=$(get_nginx_conn)
    APACHE_CONN=$(get_apache_conn)

    log "Current CPU Usage: ${CPU_USAGE}%"
    log "Current number of active Nginx connections: ${NGINX_CONN}"
    log "Current number of active Apache connections: ${APACHE_CONN}"

    # Reset trigger flags
    TRIGGER_CPU=0
    TRIGGER_CONN=0
    TRIGGER_APACHE=0

    # CPU logic: increase counter if threshold exceeded, otherwise reset
    if [ "$CPU_USAGE" -gt "$CPU_THRESHOLD" ]; then
        CPU_EXCEED_COUNT=$((CPU_EXCEED_COUNT+1))
        log "CPU threshold exceeded. CPU_EXCEED_COUNT = ${CPU_EXCEED_COUNT}"
        # Trigger if threshold exceeded 5 times in a row
        if [ "$CPU_EXCEED_COUNT" -ge 5 ]; then
            TRIGGER_CPU=1
            CPU_EXCEED_COUNT=0
        fi
    else
        CPU_EXCEED_COUNT=0
    fi

    # Nginx connections logic
    if [[ "$NGINX_CONN" =~ ^[0-9]+$ ]] && [ "$NGINX_CONN" -gt "$CONN_THRESHOLD" ]; then
        TRIGGER_CONN=1
    fi

    # Apache connections logic
    if [[ "$APACHE_CONN" =~ ^[0-9]+$ ]] && [ "$APACHE_CONN" -gt "$APACHE_CONN_THRESHOLD" ]; then
        TRIGGER_APACHE=1
    fi

    # Check if any trigger condition is met
    if [ "$TRIGGER_CPU" -eq 1 ] || [ "$TRIGGER_CONN" -eq 1 ] || [ "$TRIGGER_APACHE" -eq 1 ]; then
        REASON=""
        [ "$TRIGGER_CPU" -eq 1 ] && REASON+="CPU usage exceeded (over ${CPU_THRESHOLD}% for 5 consecutive checks). "
        [ "$TRIGGER_CONN" -eq 1 ] && REASON+="Nginx connections exceeded (${NGINX_CONN} > ${CONN_THRESHOLD}). "
        [ "$TRIGGER_APACHE" -eq 1 ] && REASON+="Apache connections exceeded (${APACHE_CONN} > ${APACHE_CONN_THRESHOLD})."
        log "Overload conditions detected: $REASON"

        # Send email notification
        send_email "Activating 'under_attack' mode" "Switching Cloudflare to '${SECURITY_LEVEL_ATTACK}' mode due to: $REASON"

        # Switch Cloudflare to under_attack mode
        set_cf_security_level "$SECURITY_LEVEL_ATTACK"

        log "Maintaining '${SECURITY_LEVEL_ATTACK}' mode for ${ATTACK_DURATION} seconds."
        SECONDS_PASSED=0
        while [ $SECONDS_PASSED -lt $ATTACK_DURATION ]; do
            sleep 10
            SECONDS_PASSED=$((SECONDS_PASSED+10))
            if [ -f /tmp/cloudflare_monitor_stop ]; then
                log "Stop file found during attack mode. Exiting script."
                rm -f /tmp/cloudflare_monitor_stop
                exit 0
            fi
        done

        log "Reverting Cloudflare security level to '${DEFAULT_SECURITY_LEVEL}'"
        set_cf_security_level "$DEFAULT_SECURITY_LEVEL"
        send_email "Restoring normal mode" "Cloudflare reverted to '${DEFAULT_SECURITY_LEVEL}' mode after attack mode."
    fi

    sleep "$CHECK_INTERVAL"
done
 
Последнее редактирование:

X-Shar

:)
Администрация
Регистрация
03.06.2012
Сообщения
6 229
Репутация
8 358
CHECK_INTERVAL=10, тоже можно поменять например CHECK_INTERVAL=3.

И вот эту часть в коде тоже можно поменять:


# If threshold exceeded 5 times in a row, set TRIGGER_CPU
if [ "$CPU_EXCEED_COUNT" -ge 5 ]; then

Вместо 5 можно больше, если CHECK_INTERVAL меньше.
В общем скрипт настраиваемый.

Удачи!
 

Pushik

Пользователь
Форумчанин
Регистрация
02.02.2024
Сообщения
2
Полезные темы также:




Привет, посмотрел твой сайт через и что логично он спрятан за CDN Cloudflare, также я смотрел способы поиска реального ip сайта за WAF:
и там он чекает везде переходом по ip которые находит, сам я пока не настраивал Cloudflare но если "Настроить брандмауэр (например, UFW, iptables через панель управления сервером), чтобы блокировать весь трафик, кроме Cloudflare." ip никак не узнать их не почекать так?
 

X-Shar

:)
Администрация
Регистрация
03.06.2012
Сообщения
6 229
Репутация
8 358
Я рекомендую перевести файервол в режим DROP всех и прописать доступ только к нужным портам, если за облаком, то дать доступ к спискам айпи облака для нужных портов.

Также ssh, как минимум перенести на нестандартный порт.

Тогда айпи не будет отвечать даже на пинги, типо он не онлайн, хотя на самом деле будет работать сайт.)

Ну тут надо понимать, что есть атаки на хостинг, это уровни L2-L4, желательно что-бы у хостинга была защита.

Либо тогда нужно арендавать чистый и не засвеченный вашем сайтом нигде айпи.

Также закрыть уязвимости раскрытия айпи, это как минимум рассылка с сервера почты и настройки dns.

Еще хочу отметить что бесплатный тариф CloudFlare, он условно бесплатный, все зависит на сколько вы будете создавать там нагрузку, и как сильно будут ддосить.

Короче могут преложить перейти на энтерпрайз тариф, а там цены уже другие.)
 

Pushik

Пользователь
Форумчанин
Регистрация
02.02.2024
Сообщения
2
Я рекомендую перевести файервол в режим DROP всех и прописать доступ только к нужным портам, если за облаком, то дать доступ к спискам айпи облака для нужных портов.

Также ssh, как минимум перенести на нестандартный порт.

Тогда айпи не будет отвечать даже на пинги, типо он не онлайн, хотя на самом деле будет работать сайт.)

Ну тут надо понимать, что есть атаки на хостинг, это уровни L2-L4, желательно что-бы у хостинга была защита.

Либо тогда нужно арендавать чистый и не засвеченный вашем сайтом нигде айпи.

Также закрыть уязвимости раскрытия айпи, это как минимум рассылка с сервера почты и настройки dns.

Еще хочу отметить что бесплатный тариф CloudFlare, он условно бесплатный, все зависит на сколько вы будете создавать там нагрузку, и как сильно будут ддосить.

Короче могут преложить перейти на энтерпрайз тариф, а там цены уже другие.)
спасибо!
 
Верх Низ