Як шифрується
TLS 1.3 in transit (Let's Encrypt). Зовнішні API-ключі, банківські токени та брокерські секрети — AES-256-GCM з унікальним IV на запис. Паролі — bcrypt (12 раундів). Ключ шифрування живе в env, не в БД.
Безпека
MyFina — домашня бухгалтерія. Фінансові дані у нас на особливому рахунку: показуємо як вони захищені без маркетингу.
Три короткі відповіді на головні запитання
TLS 1.3 in transit (Let's Encrypt). Зовнішні API-ключі, банківські токени та брокерські секрети — AES-256-GCM з унікальним IV на запис. Паролі — bcrypt (12 раундів). Ключ шифрування живе в env, не в БД.
PostgreSQL 16 у керованому інстансі в Hetzner (Німеччина, ЄС). Ізольована Docker-мережа, жодних зовнішніх підключень до БД. Резервні копії — щоденні, шифруються перед завантаженням, retention 30 днів.
Hard-delete акаунта в одному кадрі: каскадно видаляються транзакції, рахунки, категорії, валюти, токени. Без soft-delete-таблиць, без архіву «на всяк випадок». Маркетинг-ліди за тим самим email — окремий erase-hook (GDPR Art. 17).
Шість стовпів захисту
NextAuth.js v5 на JWT, пароль хешується bcrypt. Логін-тротлінг 5 спроб / 15 хв на ідентифікатор та 20 / 15 хв на IP. OAuth Google за вибором. Скидання пароля — 32-байтний токен, у БД лише SHA-256.
Зовнішні API-ключі (банки, Resend, Anthropic) і брокерські секрети шифруються AES-256-GCM. Ключ шифрування ніколи не залишає сервер. Per-connection webhook-секрети — 32-байт hex для кожної банківської інтеграції.
Кожна UPDATE/DELETE-операція фільтрується за `userId`. IDOR-захист централізовано в `assertCanAccessAccount/Category` — спроба доступу до чужого рахунку дає 403, не 404. Сімейні рахунки працюють через явні ролі OWNER/MEMBER/VIEWER.
JWT з інкрементним `session_version`. Зміна пароля, блокування користувача чи зміна ролі інвалідують усі активні сесії. Refresh-токени мобільного API ротуються при кожному оновленні.
Hard-delete акаунту видаляє всі транзакції, рахунки, категорії каскадно в одній транзакції. Експорт даних — CSV/XLSX/PDF одним кліком. Cookie consent з двома категоріями (essential / functional), без аналітики й трекерів.
Усі адмін-дії та чутливі користувацькі операції пишуться в `audit_log` з IP, user-agent і source. Логи спроб входу зберігаються 30 днів. Webhook-події Stripe — окремий idempotency-журнал для replay при збоях.
Що ми НЕ робимо
Якщо ви підключаєте Monobank або PSD2-банк через GoCardless, ми отримуємо лише те, що потрібно для синхронізації транзакцій: вихідні платежі, вхідні перекази, баланси рахунків. Жодних персональних даних банку (паспорт, фото, біометрія). API-токен банку зберігається зашифрованим AES-256-GCM; ви можете відкликати доступ в один клік з Налаштування → Банки. GoCardless-згода спливає кожні 90 днів за вимогою PSD2 — ми нагадуємо за 7 днів.
Глибше в деталі
Повний список сторонніх сервісів, що обробляють ваші дані: Hetzner (хостинг), Stripe (білінг), Resend (email), Anthropic (AI, DRAFT), GoCardless (PSD2), Monobank API, FCM.
Відкрити списокPer-feature матриця: що зберігається, як довго, як видаляється. GDPR Art. 15/17/20 запити й retention-вікна по кожній сутності.
Відкрити матрицюЧасті запитання про безпеку
Сервери — у дата-центрі Hetzner у Франкфурті, Німеччина (ЄС). Юридичним контролером даних є власник MyFina; жодних агрегаторів-посередників, жодних US-cloud-провайдерів. Повний список субпроцесорів — на /security/subprocessors.
Мінімум за 30 днів ми надішлемо email із попередженням і кнопкою «Завантажити все» у форматах CSV / XLSX / PDF. Після grace-періоду БД буде знищена. Це операційне зобов'язання в умовах сервісу, а не маркетингова обіцянка.
Так. Налаштування → Дані → Видалити акаунт — це hard-delete в одній БД-транзакції: каскадно стираються транзакції, рахунки, категорії, токени, маркетингові ліди за тим же email. Без soft-delete, без архівів «про всяк випадок». Відповідає GDPR Art. 17 («право бути забутим»).
Ніхто з «персоналу» не має routine-доступу до фінансових рядків користувачів. Власник може отримати доступ до БД лише під час інциденту безпеки або за вашим явним зверненням у support. Усі адмін-дії пишуться в audit_log із IP та user-agent.
Сесія в браузері — це JWT із TTL, не «назавжди залогінений». Якщо хтось отримає фізичний доступ до ноутбука, а поточний браузер уже розлогінений — без пароля увійти не можна. Якщо сесія активна — рекомендуємо використовувати lock-screen ОС і/або змінити пароль з іншого пристрою (це інвалідує всі активні сесії).
Ні. Ми не запускаємо жодного аналітичного скрипта на користувацьких сторінках. Cookie-банер показує лише дві категорії — essential (NextAuth-сесія) та functional (реферальні посилання). Без analytics-категорії, тому що її немає.
Що ви можете перевірити самі
Усі твердження вище — перевіряємі через код та API.
src/lib/crypto.ts (AES-256-GCM, randomBytes IV, auth tag).src/auth.ts, src/lib/auth/rate-limit.ts.src/lib/auth/ownership.ts (assertCanAccessAccount).https://app.my-fina.com/api/openapi (OpenAPI 3.1).https://app.my-fina.com/api/health (публічний liveness).Підпишіться, щоб дізнаватися про CVE, патчі безпеки та зміни моделі загроз. Жодного маркетингу.