# Серверный слой защиты боевого сервера (SEC-1..SEC-7) — установка и управление **Статус:** развёрнут на боевом тест-сервере `liderra.ru` 22.05.2026. Это серверный слой защиты (инфраструктура), вынесенный из A8 infosec-tooling эпика как открытые вопросы SEC-1..SEC-7 (ADR-014 §9). Источник фактов и истории — `memory/project_server_hardening.md`. Сервер: VM `liderra-test` (Ubuntu 24.04), `ssh -i ~/.ssh/liderra_deploy ubuntu@111.88.246.137` (доступ только по ключу, пароль отключён). Стек на одной VM: nginx 1.24 / php8.3-fpm / PostgreSQL 16 / redis. **Ресурсы тесные: 1.9 ГБ RAM / 2 CPU / ~12 ГБ свободно диска** → тяжёлые сервисы (self-host Sentry ~4 ГБ+) не помещаются. **Гигиена изменений (соблюдалась везде):** перед каждым изменением nginx — `cp` бэкап конфига + `nginx -t` + `reload`-или-восстановление из бэкапа при провале `nginx -t`. Все правки через `reload` (не `restart`) — простоя сайта не было. Изменения файловые → переживают reboot. | SEC | Тема | Статус | |---|---|---| | SEC-1 | WAF (веб-фаервол) | ✅ боевой режим | | SEC-2 | Анти-перебор паролей | ✅ сделано | | SEC-3 | DDoS-защита | ⏸ отложено (цена) | | SEC-4 | Мониторинг + алертинг | ✅ лёгкий | | SEC-5 | Хранилище секретов | 🟦 частично (app-интеграция блокирована) | | SEC-6 | TLS / HSTS / CSP | ✅ сделано | | SEC-7 | Бэкапы + реагирование | ✅ бэкапы; IR-runbook реюз | --- ## SEC-6 — HTTPS + защитные заголовки ✅ Был **только HTTP** (пароли/ПДн открытым текстом). Развёрнут certbot Let's Encrypt для `liderra.ru` + `www.liderra.ru` (`/etc/letsencrypt/live/liderra.ru/`, авто-обновление certbot). nginx переписан в **2 server-блока** (`/etc/nginx/sites-available/liderra`, симлинк в `sites-enabled`): - `:80` → редирект на https, **кроме** `/.well-known/acme-challenge/` (certbot) и `^~ /api/webhook/` (вебхуки поставщика могут не следовать за 301 на POST → оставлены доступными по http). - `:443` → приложение + защитные заголовки. Заголовки на `:443`: ```nginx add_header Strict-Transport-Security "max-age=604800" always; # 1 неделя — умеренно/обратимо add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; ``` **NB про Basic-Auth «дверь»:** ранее перед сайтом стоял Basic-Auth барьер; **убран 22.05.2026 по явной информированной просьбе заказчика** (данные остаются за app-логином). Восстановить: вернуть `auth_basic "Liderra test"; auth_basic_user_file /etc/nginx/.htpasswd;` в `location /` блока `:443` из бэкапа `liderra.bak-*`. Связка с приложением: `APP_URL=https://liderra.ru` + `SANCTUM_STATEFUL_DOMAINS=liderra.ru,www.liderra.ru` в `/var/www/liderra/app/.env` (cookie-логин на apex+www). После правки `.env` обязателен `php artisan config:cache` (запускать **от `ubuntu`** — владелец `.env` + `bootstrap/cache`; php-fpm = www-data читает по правам). **CSP** — см. отдельную секцию ниже (SEC-6 CSP). --- ## SEC-2 — анти-перебор паролей ✅ Прикладной слой **уже был** (`AuthController` RateLimiter, `LOGIN_MAX_ATTEMPTS=5`, лок по email+IP). Добавлен **fail2ban** (`/etc/fail2ban/jail.local`): jails `sshd` (maxretry 4) + `nginx-http-auth` (порты http,https, лог `/var/log/nginx/error.log`), `bantime 1h`, `findtime 10m`, `ignoreip 127.0.0.1/8 ::1`, backend systemd. Активен + enabled. Фон атак реальный: отчёт показал **~1408 неудачных SSH-попыток/сутки**. SSH — только по ключу (пароль отключён), поэтому свой доступ fail2ban не банит. Управление: `sudo fail2ban-client status`, `sudo fail2ban-client status sshd`. --- ## SEC-1 — WAF (ModSecurity + OWASP CRS) ✅ боевой режим Пакеты `libnginx-mod-http-modsecurity` 1.0.3 + `modsecurity-crs` 3.3.5. Движок `/etc/modsecurity/modsecurity.conf` (создан вручную — пакет CRS не несёт движковый конфиг): `SecRuleEngine On`, `SecResponseBodyAccess Off` (ради памяти), audit `/var/log/modsec_audit.log` RelevantOnly. Порог блокировки CRS — дефолт 5 (inbound anomaly). Загружено **1830 правил**. **Подключение** `/etc/nginx/modsec/main.conf` + `modsecurity on; modsecurity_rules_file ...` в обоих server-блоках. **ВАЖНО:** НЕ использовать `/usr/share/modsecurity-crs/owasp-crs.load` — там Apache-директива `IncludeOptional`, которую nginx-коннектор (libmodsecurity v3) не понимает (`nginx -t` падает). Вместо неё в `main.conf` явный порядок `Include`: ``` modsecurity.conf → crs-setup.conf → liderra-exclusions.conf → REQUEST-900-EXCLUSION-BEFORE → /usr/share/modsecurity-crs/rules/*.conf → RESPONSE-999-EXCLUSION-AFTER ``` ### Исключение вебхука поставщика Новый файл `/etc/nginx/modsec/liderra-exclusions.conf` (вне пакета CRS → переживает обновления `modsecurity-crs`): ``` SecRule REQUEST_URI "@beginsWith /api/webhook/" \ "id:1900100,phase:1,pass,nolog,ctl:ruleEngine=DetectionOnly" ``` Приём лидов — деньги бизнеса, и он уже защищён на уровне приложения (HMAC + rate-limit + SSRF-guard), поэтому WAF на нём только наблюдает: ложное срабатывание = потерянный лид. URI-based (а не per-location nginx) — надёжно при `try_files`→`/index.php`. ### Фикс: WAF разрешил REST-методы (важно) После включения боевого режима правило CRS **911100 «Method is not allowed by policy»** блокировало `PATCH`/`DELETE`/`PUT` (CRS-дефолт разрешает только GET/HEAD/POST/OPTIONS) → молча ломало редактирование/удаление в портале. Фикс — в `/etc/modsecurity/crs/crs-setup.conf` (бэкап `crs-setup.conf.bak-*`): ``` SecAction "id:900200,phase:1,nolog,pass,t:none,\ setvar:'tx.allowed_methods=GET HEAD POST OPTIONS PUT PATCH DELETE'" ``` Грузится **до** 901-init (который ставит дефолт условно `&TX:allowed_methods @eq 0`). NB: попытка через `liderra-exclusions.conf` (id:1900200) НЕ сработала — фикс работает только в `crs-setup.conf`. ### Проверка боевого режима ```bash curl -s -o /dev/null -w "%{http_code}\n" https://liderra.ru/.env # → 403 (WAF блок) curl -s -o /dev/null -w "%{http_code}\n" "https://liderra.ru/?x=