Repository navigation
12 Security
Модель угроз простая: это интернет-приложение, которое физически открывает ворота и хранит персональные данные жителей. Поэтому защита многослойная.
| Роль | Что может |
|---|---|
admin |
всё (*), включая настройки, пользователей, бэкапы, обновления |
operator |
жители (view/create/edit), касса (приём оплат, начисления, перерасчёт), шлагбаум (open, журнал), гостевые, рассылки, объявления, экспорт, просмотр логов/аудита |
resident |
свой кабинет: открыть свой шлагбаум, свои гостевые, свои счета |
40+ точечных прав (Permissions::ALL) применяются middleware Authorize
по опциям маршрутов + дополнительно в контроллерах
(Guard::requirePermission). Жители ограничены строково: каждый запрос
сверяет resident_id с сессией. API-токены дают области, а не роли —
утёкший токен автоматизации не станет админской сессией.
- пароли:
argon2id(при наличии sodium) иначе bcrypt; политика длины/ сложности, история паролей (нельзя повторять последние N), опциональная проверка утечек (haveibeenpwned, k-anonymity); - блокировка после 5 неудач на 30 мин + журнал входов + защита от перечисления логинов (одинаковый ответ «неверная пара»);
-
2FA TOTP (Google Authenticator и совместимые): обязательна для ролей
из
two_factor.required_for(default: admin) с grace-периодом 7 дней, recovery-коды (8 шт.); сброс админомuser:2fa-reset; - «запомнить меня» — подписанная ротационная cookie (30 дней), отзываемая;
- сессии: HttpOnly + SameSite=Lax + Secure(авто) +
__Secure-prefix на HTTPS, absolute lifetime 12 ч, idle 60 мин, регенерация ID при логине, опциональная привязка к отпечатку UA/IP, таблица сессий с отзывом из UI, «выйти везде» при смене пароля.
- CSP
default-src 'self', скрипты только'self'+ per-request nonce (никаких inline-скриптов иunsafe-eval), стили'unsafe-inline'(нужен theme-bootstrap'у — одна переменная),frame-ancestors 'self',object-src 'none',base-uri/form-action 'self'; -
X-Frame-Options: SAMEORIGIN,X-Content-Type-Options: nosniff,Referrer-Policy: strict-origin-when-cross-origin,Permissions-Policy(камера/микрофон/геолокация выключены), HSTS на HTTPS,Cross-Origin-Opener/Resource-Policy; -
Cache-Control: no-storeна весь динамический HTML/JSON (приватные данные не должны оседать в кэшах); длинные кэши — только на fingerprinted-ассеты; - заголовки ставятся на всех путях, включая страницы ошибок.
- SQL — только prepared statements (PDO); сырые фрагменты — только через
явные
Expressionв миграциях/диалектах; - вывод — экранирование
$this->e()во всех шаблонах; Markdown-рендер справки санитизирует HTML; - CSRF — synchronizer-token на все POST (форма-поле
_tokenили заголовокX-CSRF-Token), TTL 2 ч, ротация при логине; исключения — подписанные гостевые ссылки (HMAC вместо сессии) и telegram-webhook (свой секрет); - подписанные URL гостевых пропусков: токен 48 hex + HMAC ключом приложения, подобрать нельзя, отзыв мгновенный;
- загрузки: whitelist расширений (csv/json/txt/xlsx), лимит 10 МБ, хранение вне web-рут, парсинг без выполнения;
- mass-assignment исключён: контроллеры берут явные поля через валидатор.
Отдельные лимиты: логин 5/15 мин, gate_open 12/мин + cooldown устройства,
guest_create 8/час, guest_open 20/мин, password_reset 3/час,
API 120/мин. 429 + Retry-After. Хранение — файл/кэш с GC по cron.
-
.bas-ip.config.local.phpвне git, права 0600 (установщик выставляет сам,doctorпроверяет); - шифрование секретов at-rest:
storage/+ ключ приложения (AES-256-GCM) — пароли устройств, бот-токены (secret:set/list/forget/reencrypt); - маскирование в логах:
password, token, secret, authorization, cookie, otp— автоматически (logging.redact); - API-токены хранятся хэшами, показываются один раз;
- пароль устройства в устанавливаемом конфиге —
${secret:DEVICE_PASSWORD}, не plaintext.
-
audit_log: каждое значимое действие — актёр (user/api/system), действие, субъект (resident/charge/device/…), meta, IP, request_id; экспорт; - журнал входов (успех/неудача/блокировки/2FA), сессии;
- каналы логов: app, access, audit, gate, device, notify, error, update —
с ротацией по дням и политикой хранения (
prune); -
/health.json+/metricsдля мониторинга;X-Request-Idсквозной.
- документ-рут — только
public/; корень закрыт.htaccess; nginx-конфиг из wiki запрещает dotfiles; -
auth.ip_allowlist— админка/API только со своих IP (опция); - режим обслуживания закрывает UI, не блокируя открытие ворот (жители не должны страдать от деплоя);
- установщик самоблокируется (
install.lock, 403 после установки); - обновления: checksum артефакта (опционально pin SHA-256), бэкап файлов и БД перед установкой, preserve-список (конфиг/storage не перезаписываются), откат.
- HTTPS (Let's Encrypt),
app.urlсhttps://, HSTS включён. -
env=production,debug=false. - Уникальный
app.key(сгенерирован установщиком). - Права:
storage0750/www-data, конфиг 0600, код 0640 root. - 2FA включена у всех staff; пароли уникальные.
- Отдельная БД-учётка без FILE/SUPER-прав; БД не наружу.
- API-токены: минимальные scopes, сроки, отдельные на интеграцию.
-
ip_allowlistдля админки, если есть постоянные IP. - cron:
schedule:run+backup:create; бэкапы — offsite. - Мониторинг
/healthи логовerror/audit(is_security: true). -
php bin/bas-ip doctor— 0 ошибок, предупреждения закрыты. - Если использовался v1 — отозвать старый
.api_tokenпанели.
Только приватно — SECURITY.md. Публичные issue по безопасности удаляются.
Дальше: 13 · Бэкап и восстановление