security: устранить находки аудита, версия 1.1.7

Конфигурация и эксплуатационный слой:
- nginx: client_max_body_size 64m — восстановление из бэкапа не работало
  вовсе, дефолтный лимит в 1 МБ резал дампы (реальный экспорт ~3.4 МБ)
  с 413 ещё до backend;
- nginx: заголовки безопасности (nosniff, Referrer-Policy,
  Permissions-Policy) и полный Content-Security-Policy. Ради него
  inline-скрипт темы вынесен в public/theme-init.js;
- nginx: limit_req на /api/ — перебор пароля Basic Auth шёл со
  скоростью сети, ни блокировки, ни задержки не было;
- nginx: server_tokens off;
- порт web привязан к 127.0.0.1, адрес настраивается через
  AURUM_BIND_ADDRESS (раньше слушался на всех интерфейсах);
- backend работает от непривилегированного пользователя,
  no-new-privileges для backend и web;
- дефолты пароля Postgres сведены к одному значению в обоих сервисах,
  в .env.example описана ловушка с инициализацией тома.

Приложение:
- версия убрана из неавторизованного /api/health и отдаётся как
  app_version в GET /api/settings;
- /api/docs, /api/redoc и /api/openapi.json отключаются через
  AURUM_ENABLE_DOCS;
- текст исключения при неудачном восстановлении уходит в лог, а не
  клиенту;
- max_length для notes в схемах транзакций, активов и регулярных
  платежей (и в соответствующих полях UI);
- срок «запомнить меня» сокращён с 30 дней до 7;
- pytest обновлён до 9.0.3 (PYSEC-2026-1845), pytest-asyncio до 1.4.0;
- CI: permissions contents:read для GITHUB_TOKEN.
This commit is contained in:
ZProger
2026-09-10 21:12:31 +03:00
parent eba8add92f
commit f9413aa6e1
27 changed files with 268 additions and 78 deletions

15
DOCS.md
View File

@@ -116,9 +116,13 @@ string.
### `GET /api/health`
No auth required. Returns `{"status": "ok", "version": "1.1.0"}` — `version` is the running app's
version, the same value shown in the UI under Settings. Use this to check the backend is up before
hitting anything else.
No auth required. Returns `{"status": "ok"}`. Use this to check the backend is up before hitting
anything else.
This response deliberately carries nothing else. It used to include the running app version, but
this is the one endpoint served without authentication — handing the exact release to anyone who
can reach the instance tells them which known issues it still has. The version now comes back as
`app_version` from `GET /settings`, which sits behind auth like everything else.
## Accounts
@@ -763,10 +767,13 @@ Single row, created automatically on first run — there's nothing to create, on
"net_worth_decline_threshold_months": 2,
"risky_allocation_threshold_percent": 20,
"idle_cash_threshold_amount": "1000.00",
"idle_cash_threshold_days": 60
"idle_cash_threshold_days": 60,
"app_version": "1.1.7"
}
```
- `app_version`: read-only, ignored on `PATCH` — the running app's release, shown in the UI under
Settings. It lives here rather than on the unauthenticated `/health`.
- `currency`: 3-letter uppercase code — display-only, no conversion.
- `negative_cash_flow_threshold_months` / `net_worth_decline_threshold_months`: consecutive months
before the corresponding alert fires (`1`–`24`).