Files
wt da9e17f45f
Android CI / Build and Test (push) Failing after 13m25s
iOS CI / Build and Test SwiftUI App (push) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build Unsigned iOS IPA (push) Canceled after 0s
Build Unsigned iOS and macOS Apps / Build macOS ZIP (push) Canceled after 0s
added AGENTS.md and docs in root dir
2026-09-08 13:36:43 +07:00

96 lines
4.9 KiB
Markdown

# Безопасность (сквозные требования)
Этот документ собирает требования безопасности, которые применяются
ко **всем** подпроектам одновременно. Платформенно-специфичные детали —
в [`BalanceServer/docs/SECURITY.md`](../BalanceServer/docs/SECURITY.md),
`Balance/AGENTS.md` (раздел «Безопасность») и
`BalanceAndroid/AGENTS.md` (раздел «Security»).
## Хранение секретов на клиентах
| | Apple | Android |
| --- | --- | --- |
| Access/refresh токены | Keychain (service `BalanceServer`) | зашифрованное хранилище через Android Keystore (AES/GCM), `SecureSessionStore` |
| Несекретные настройки (URL сервера, cursor, sync metadata) | `UserDefaults` | `ServerPreferences` |
| Запрещено | пароль в `UserDefaults`, SwiftData или файлах | токены в обычных `SharedPreferences` |
Ни один клиент не должен хранить пароль пользователя после
аутентификации — только access/refresh токены.
## Хранение секретов на сервере
- Пароли — только Argon2id-хеши, plaintext никогда не сохраняется.
- Refresh-токены хранятся как SHA-256 хеши, не в открытом виде.
- `BALANCE_JWT_SECRET` должен быть случайной строкой не короче 32
символов; его смена инвалидирует access-токены (refresh-сессии
остаются валидны и получают новый access-токен при следующем
refresh).
## Транспорт
- Для удалённого (не-localhost) сервера все клиенты обязаны
использовать HTTPS.
- HTTP разрешён клиентам **только** для `localhost`, `127.0.0.1` и
`::1` — это относится и к Apple-, и к Android-клиенту.
- Production-деплой сервера должен работать через HTTPS/TLS
(например, через reverse proxy — Caddy/nginx), см.
[`BalanceServer/README.md#https`](../BalanceServer/README.md#https).
## Логирование
Запрещено логировать на любой из трёх платформ:
- пароли;
- access/refresh токены;
- заголовок `Authorization` целиком;
- полные request bodies с финансовыми данными без явной необходимости.
Безопасно логировать (на сервере): request ID, endpoint, status code,
latency, размер batch, неконфиденциальные идентификаторы записей.
## Авторизация на сервере
Каждая sync-мутация обязана проверять ownership по authenticated user
из токена/сессии. Никогда не доверяй `userId`, пришедшему в теле
запроса от клиента, если identity уже известна из
Authorization-заголовка или cookie-сессии:
```text
Authorization header / session cookie
↓
authenticated user
↓
server-side ownership check
↓
requested entity
```
## Валидация входных данных (сервер)
Проверяются: UUID/ID, enum-значения, `amount`, timestamps, длины строк,
размер batch, размер JSON, границы cursor/sequence.
## Защита от злоупотреблений (production-деплой сервера)
- rate limiting для auth-эндпоинтов (встроенный лимитер — 30
auth-запросов на IP в минуту; для более сильного публичного
rate limiting используйте reverse proxy);
- разумные ограничения на размер тела запроса;
- таймауты и graceful shutdown;
- ограничение подключений к БД;
- мониторинг.
## Секреты в репозитории
Ни в одном из трёх подпроектов не должны появляться:
- production URL серверов;
- реальные `BALANCE_JWT_SECRET` или иные секреты;
- закоммиченные `.env`, keystore-файлы, сертификаты;
- захардкоженные тестовые credentials, которые могут быть спутаны с
боевыми.
`.env.example` в `BalanceServer/` и `local.properties.example` в
`BalanceAndroid/` — единственные допустимые «примерные» файлы с
конфигурацией; реальные значения в них не хранятся.