Cómo se cifra
TLS 1.3 en tránsito (Let's Encrypt). Claves de API externas, tokens bancarios y secretos de brokers — AES-256-GCM con un IV único por registro. Contraseñas — bcrypt (12 rondas). La clave de cifrado vive en env, no en la base de datos.
Seguridad
MyFina es una contabilidad doméstica. Los datos financieros son especiales — aquí te contamos cómo los protegemos, sin paja de marketing.
Tres respuestas breves a las grandes preguntas
TLS 1.3 en tránsito (Let's Encrypt). Claves de API externas, tokens bancarios y secretos de brokers — AES-256-GCM con un IV único por registro. Contraseñas — bcrypt (12 rondas). La clave de cifrado vive en env, no en la base de datos.
PostgreSQL 16 en una instancia gestionada en Hetzner (Alemania, UE). Red Docker aislada, sin conexiones externas a la BD. Copias de seguridad — diarias, cifradas antes de subirlas, retención de 30 días.
Hard-delete de la cuenta en un solo paso: se eliminan en cascada transacciones, cuentas, categorías, divisas, tokens. Sin tablas soft-delete, sin archivo «por si acaso». Leads de marketing bajo el mismo email — erase-hook independiente (GDPR Art. 17).
Seis pilares de defensa
NextAuth.js v5 sobre JWT, contraseñas con hash bcrypt. Throttling de login — 5 intentos / 15 min por identificador y 20 / 15 min por IP. OAuth de Google opcional. Reset de contraseña con un token de 32 bytes; solo se guarda su SHA-256.
Las claves de API externas (bancos, Resend, Anthropic) y los secretos de brokers se cifran con AES-256-GCM. La clave nunca abandona el servidor. Cada conexión bancaria lleva su propio secreto de webhook hex de 32 bytes.
Cada operación UPDATE/DELETE filtra por `userId`. La protección IDOR está centralizada en `assertCanAccessAccount/Category` — el acceso a la cuenta de otro devuelve 403, no 404. Las cuentas familiares compartidas usan roles explícitos OWNER/MEMBER/VIEWER.
JWT con un `session_version` que se incrementa. Cambio de contraseña, bloqueo de cuenta o cambio de rol invalidan todas las sesiones activas. Los refresh tokens de la API móvil rotan en cada refresh.
El hard-delete de la cuenta elimina todas las transacciones, cuentas y categorías en cascada en una sola transacción. Exportación de datos — CSV/XLSX/PDF con un clic. Cookie consent con dos categorías (essential / functional), sin analítica ni trackers.
Todas las acciones de admin y operaciones sensibles del usuario se escriben en `audit_log` con IP, user-agent y source. Los logs de intentos de login se guardan 30 días. Los eventos de webhook de Stripe se sientan en un journal de idempotency dedicado para replay seguro en caso de fallo.
Lo que NO hacemos
Si conectas Monobank o un banco PSD2 a través de GoCardless, solo recibimos lo necesario para sincronizar transacciones: pagos salientes, transferencias entrantes, saldos de cuentas. Ningún dato personal del lado del banco (pasaporte, foto, biometría). El token de API del banco se guarda cifrado con AES-256-GCM; puedes revocar el acceso con un clic desde Ajustes → Bancos. El consentimiento de GoCardless caduca cada 90 días según PSD2 — te recordamos con 7 días de antelación.
Detalles más profundos
Lista completa de servicios de terceros que procesan tus datos: Hetzner (hosting), Stripe (facturación), Resend (email), Anthropic (AI, DRAFT), GoCardless (PSD2), Monobank API, FCM.
Abrir listaMatriz per-feature: qué se almacena, cuánto tiempo, cómo se elimina. Flujo GDPR Art. 15/17/20 y ventanas de retención por entidad.
Abrir matrizLo que puedes verificar tú mismo
Cada afirmación de arriba es auditable vía código y 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 público).Suscríbete para enterarte de CVEs, parches de seguridad y cambios en el modelo de amenazas. Sin marketing.