fe122b7681
- security_events (миграция 047) + utils/securityLog.js (defensive, lazy stmt) - Tier 1: login.success/fail, register, password.change в authController - Tier 2: 403 (роль/разрешение) в middleware/auth, rate_limited в rateLimit - Tier 3: audit() на выдачу доступа (access), начисление/сброс XP (gam), модерацию аватаров - API GET/DELETE /api/admin/security-log (фильтр по категории + поиск, прунинг по дням) - Frontend: вкладка «Безопасность» в admin.html + loadSecurityLog, расширены ACTION_LABELS Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
34 lines
1.9 KiB
SQL
34 lines
1.9 KiB
SQL
-- 047_security_events.sql
|
|
-- Журнал событий безопасности и входа (Tier 1 + Tier 2 плана логирования).
|
|
--
|
|
-- Отдельная таблица, НЕ admin_audit_log, потому что:
|
|
-- • автор часто аноним (у неудачного логина ещё нет user_id);
|
|
-- • объём может быть большим (боты долбят логин / rate-limit);
|
|
-- • свой ретеншн (чистится агрессивнее, чем осознанные админ-действия).
|
|
-- admin_audit_log остаётся домом для привилегированных действий (Tier 3).
|
|
--
|
|
-- category:
|
|
-- auth — login.success | login.fail | register | password.change
|
|
-- access_denied — forbidden (роль) | perm_denied (разрешение)
|
|
-- rate_limit — rate_limited (превышение лимита запросов)
|
|
|
|
CREATE TABLE IF NOT EXISTS security_events (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
category TEXT NOT NULL CHECK (category IN ('auth','access_denied','rate_limit')),
|
|
event TEXT NOT NULL,
|
|
user_id INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
|
email TEXT, -- email из попытки/связанный (для анонимных)
|
|
ip TEXT,
|
|
user_agent TEXT,
|
|
method TEXT,
|
|
route TEXT,
|
|
detail TEXT,
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_sec_events_date ON security_events (created_at DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_sec_events_category ON security_events (category, created_at DESC);
|
|
CREATE INDEX IF NOT EXISTS idx_sec_events_email ON security_events (email);
|
|
CREATE INDEX IF NOT EXISTS idx_sec_events_ip ON security_events (ip);
|
|
CREATE INDEX IF NOT EXISTS idx_sec_events_user ON security_events (user_id);
|