WAF (брандмауэр)
Вкладка WAF — сетевой брандмауэр уровня приложения. В отличие от Блокировок (которые отвечают за UID / Telegram ID / fingerprint), WAF работает на уровне сетевых запросов: IP, CIDR, страна, заголовки, rate-limit, brute-force.
init.conf (секция WAF), ручные баны — в database/waf_bans.json.Что делает WAF
WAF — это middleware, который выполняется до всех остальных хендлеров (включая /lite/*, /proxy/*, админ-панель). Запрос проходит проверки в следующем порядке:
- Trusted cluster — запросы от primary-узла кластера пропускаются без проверок (см. Cluster)
- Whitelist IP / Whitelist путей — мгновенный пропуск, без дальнейших проверок
- Bypass local IP — RFC1918 + loopback пропускаются если опция включена
- Ручные баны — IP/CIDR с TTL, добавляются прямо из админки
- IP deny / allow — статический список из конфига
- Country deny / allow — фильтр по GeoIP (требует GeoIP базу)
- Headers deny — регулярные выражения по значениям HTTP-заголовков
- Brute-force — лимит уникальных device-id с одного IP за минуту
- 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,kidregex— Go-регулярка поr.URL.Path(без query-string)limit— сколько запросов разрешено заsecondspathId— учитывать последний сегмент пути как ключ (/lite/foo/123и/lite/foo/456считаются отдельно)queryIds=a,b— учитывать значения query-параметровaиbкак часть ключа
Sliding window: каждый запрос помечается UnixNano, при проверке отбрасываются записи старше seconds. Если в окне больше limit — HTTP 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 |6030 запросов в минуту на админ-пути — этого с запасом хватит обычному админу, но остановит брутфорс.
4. «Заблокировать ботов»
В «HTTP-заголовки — deny»:
User-Agent|bot|crawl|spider|scan|curl|wget|python-requestsbot. Если ваш сервер должен быть индексируемым — будьте точнее.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