WAF (брандмауэр)

WAF (брандмауэр)

Вкладка WAF — сетевой брандмауэр уровня приложения. В отличие от Блокировок (которые отвечают за UID / Telegram ID / fingerprint), WAF работает на уровне сетевых запросов: IP, CIDR, страна, заголовки, rate-limit, brute-force.

Hot-reload — все изменения применяются мгновенно, перезапуск сервера не требуется. Конфиг сохраняется в init.conf (секция WAF), ручные баны — в database/waf_bans.json.

Что делает WAF

WAF — это middleware, который выполняется до всех остальных хендлеров (включая /lite/*, /proxy/*, админ-панель). Запрос проходит проверки в следующем порядке:

  1. Trusted cluster — запросы от primary-узла кластера пропускаются без проверок (см. Cluster)
  2. Whitelist IP / Whitelist путей — мгновенный пропуск, без дальнейших проверок
  3. Bypass local IP — RFC1918 + loopback пропускаются если опция включена
  4. Ручные баны — IP/CIDR с TTL, добавляются прямо из админки
  5. IP deny / allow — статический список из конфига
  6. Country deny / allow — фильтр по GeoIP (требует GeoIP базу)
  7. Headers deny — регулярные выражения по значениям HTTP-заголовков
  8. Brute-force — лимит уникальных device-id с одного IP за минуту
  9. Rate-limit — глобальный + per-route правила (sliding window)

При срабатывании любого правила WAF возвращает HTTP 403 (или 429 для rate-limit) и инкрементирует метрику. Все блокировки видны в карточке «Статистика» в реальном времени.

Глобальные переключатели

Переключатель Описание
Включить WAF Без галочки middleware работает passthrough’ом — все остальные настройки игнорируются
Пропускать локальные IP 127.0.0.0/8, ::1, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 — без проверок
Brute-force защита Лимит уникальных lampac_unic_id с одного IP за 60 секунд

Кнопки:

  • Сохранить — записать изменения в init.conf + применить
  • Из init.conf — перечитать файл и применить (без сохранения формы)
  • Обновить — обновить только статистику и список банов

Статистика (24ч / 1ч)

Три колонки в реальном времени:

  • По причинам (24ч) — счётчики срабатываний каждого правила: ipDeny, cidrDeny, countryDeny, headerDeny, bruteForce, rateLimit, manualBan, geoAllow, ipAllow
  • Топ путей (1ч) — какие URL чаще всего блокировались (полезно для обнаружения сканеров)
  • Топ IP (1ч) — какие источники атак активнее всего

Данные хранятся в памяти, при рестарте обнуляются. Окна — скользящие: 24 ring-bucket’а по часу для причин, 1ч TTL для путей/IP.

Ручные баны

Быстрая блокировка одного IP или подсети с TTL:

IP / CIDR:  203.0.113.5  или  203.0.113.0/24
TTL, сек:   3600   (0 = навсегда)
Причина:    спам, abuse, scanner...

Бан срабатывает до проверки rate-limit и работает раньше всех правил из конфига. Удобно использовать, когда подозрительный IP начал стучать прямо сейчас — не нужно лезть в init.conf.

Поле Описание
IP / CIDR Заблокированный адрес или подсеть
Причина Комментарий администратора
Истекает Дата окончания или «постоянный»
Создан Когда добавлен бан

При истечении TTL бан автоматически вычищается фоновым сборщиком (раз в 5 минут). Файл database/waf_bans.json обновляется атомарно.

Brute-force защита

Защита от перебора авторизаций: считаем количество уникальных lampac_unic_id (device id) с одного IP за 60 секунд. Если их больше лимита — IP временно блокируется.

Лимит device-id с одного IP за минуту: 20

Чем выше — мягче. Стандартное значение 20 пропускает домохозяйства с несколькими устройствами, но ловит сканеры, которые перебирают токены.

Rate-limit

Два уровня:

Глобальный limit_req

limit_req: 600    # запросов с одного IP в минуту

Применяется ко всем путям, кроме whitelist-префиксов и стрим-эндпоинтов (/proxy/, /lite/*/video, и т.п. — для них rate-limit бессмыслен).

Per-route правила limit_map

Текстовое поле, одна строка — одно правило:

regex|limit|seconds[|pathId][|queryIds=a,b]

Примеры:

^/api/admin     |60  |60
^/lite/         |120 |60  |pathId
^/api/transcode |10  |60  |queryIds=token,kid
  • regex — Go-регулярка по r.URL.Path (без query-string)
  • limit — сколько запросов разрешено за seconds
  • pathId — учитывать последний сегмент пути как ключ (/lite/foo/123 и /lite/foo/456 считаются отдельно)
  • queryIds=a,b — учитывать значения query-параметров a и b как часть ключа

Sliding window: каждый запрос помечается UnixNano, при проверке отбрасываются записи старше seconds. Если в окне больше limitHTTP 429.

Списки IP / стран

Список Эффект
White-list IP Полный пропуск всех проверок. CIDR разрешены
IP deny Блокировка точных адресов и подсетей
IP allow Если задан — пропускаются только эти, остальные блокируются
Whitelist путей (точные) /healthz, /api/version — пропускаются без проверок
Whitelist префиксы путей Всё, что начинается с префикса (/proxy/, /static/)
Страны deny ISO-2 коды стран, через запятую: CN, KP, IR
Страны allow Если задан — пропускаются только эти. Полезно если сервер только для RU/BY/KZ/UA

GeoIP база

Для фильтрации по стране нужна база MaxMind GeoLite2-Country.

# Поместите файл в:
/etc/lampac/database/GeoLite2-Country.mmdb
# или
$LAMPAC_GO_REPO_ROOT/database/GeoLite2-Country.mmdb

Скачать можно бесплатно у MaxMind после регистрации. Если базы нет — countryDeny / countryAllow игнорируются (с предупреждением в логах).

HTTP-заголовки — deny

Регулярки по значениям заголовков. По одной строке:

HeaderName|regex

Примеры:

User-Agent|curl|wget|python-requests|Go-http-client
Referer|evil\.com|spam-site\.ru
X-Forwarded-For|192\.168\.

Регулярки case-insensitive, проверяются по всему значению заголовка. Если хоть одна совпала — HTTP 403.

Не используйте слишком общие шаблоны — например User-Agent|.* заблокирует всех. Сначала проверьте регулярку на регексп-чекере, потом включайте.

API

WAF доступен через REST API. Все эндпоинты требуют админ-сессии.

Метод Путь Тело Ответ
GET /api/waf/state {config, stats, manualBans}
POST /api/waf/config wafConfig JSON новое состояние
POST /api/waf/reload новое состояние
POST /api/waf/ban {ip, ttlSec, reason} {ok, manualBans}
DELETE /api/waf/ban/{ip} {ok, manualBans}

Также все маршруты продублированы под /api/admin/waf/... (без префикса /cp_xxx/) для интеграций.

Пример: добавить бан через curl

curl -X POST https://lampac.example.com/cp_XXXXX/api/waf/ban \
  -H "Cookie: lampac_token=..." \
  -H "Content-Type: application/json" \
  -d '{"ip":"203.0.113.50","ttlSec":3600,"reason":"scanner"}'

Пример: посмотреть текущий конфиг

curl -s https://lampac.example.com/cp_XXXXX/api/waf/state \
  -H "Cookie: lampac_token=..." | jq '.config'

Типичные сценарии

1. «Меня сканируют, нужно срочно заткнуть IP»

Откройте WAF → «Ручные баны» → введите IP, TTL 3600 (1 час), причина «scanner». Применится мгновенно.

2. «Только Россия / СНГ»

В «Страны — allow» введите RU, BY, KZ, UA. Все остальные страны получат 403. Не забудьте установить GeoIP базу и добавить себя в White-list IP, если работаете не из этих стран.

3. «Защитить /api/admin от перебора паролей»

В limit_map добавьте строку:

^/cp_           |30  |60

30 запросов в минуту на админ-пути — этого с запасом хватит обычному админу, но остановит брутфорс.

4. «Заблокировать ботов»

В «HTTP-заголовки — deny»:

User-Agent|bot|crawl|spider|scan|curl|wget|python-requests
Поисковые роботы (Googlebot, YandexBot) тоже подходят под bot. Если ваш сервер должен быть индексируемым — будьте точнее.

5. «Слишком много запросов, сервер падает»

Включите WAF + поставьте limit_req: 300. 300 запросов в минуту с одного IP — обычный пользователь столько не делает. Если у вас есть «доверенные» источники (например, ваш мониторинг) — добавьте их в White-list IP.

Trusted cluster

Запросы между узлами кластера (primary → secondary) не попадают под WAF. Это важно потому что:

  • secondary-узлы получают весь трафик через primary, который уже прошёл свой WAF
  • per-IP rate-limit на secondary считал бы все запросы за один IP (primary’я) и блокировал бы всё

Определение «trusted» — по подписанному заголовку X-Lampac-Cluster-Token. См. Cluster.

Конфиг в init.conf

WAF читает свою секцию из init.conf (JSON):

{
  "WAF": {
    "enable": true,
    "bypassLocalIP": true,
    "bruteForceProtection": true,
    "bruteForceLimit": 20,
    "whiteIps": ["10.0.0.0/8"],
    "limit_req": 600,
    "limit_map": {
      "^/api/admin": { "limit": 60, "second": 60 },
      "^/lite/":     { "limit": 120, "second": 60, "pathId": true }
    },
    "ipsDeny": ["203.0.113.0/24"],
    "ipsAllow": [],
    "countryDeny": ["CN", "KP"],
    "countryAllow": [],
    "headersDeny": {
      "User-Agent": "curl|wget|python-requests"
    },
    "customWhitelistPaths": ["/healthz"],
    "customWhitelistPrefixes": ["/proxy/", "/static/"]
  }
}

Файл редактируется автоматически из админки (кнопка «Сохранить»). Менять руками — на свой страх и риск; ошибки в JSON блокируют загрузку всех WAF-настроек.

Безопасность

  • WAF-эндпоинты доступны только суперадминистратору
  • Все изменения логируются: level=info module=waf event=config_save
  • Файл waf_bans.json пишется атомарно (write-rename)
  • Срабатывания WAF попадают в телеметрию под reason-меткой

См. также

  • Блокировки — UID / TG ID / fingerprint / страна (на уровне приложения)
  • Конфиг — общая настройка init.conf и config.toml
  • Cluster — как primary-узел доверяет secondary