Saltar a contenido

Seguridad

Todas las plataformas del ecosistema se levantan sobre una misma línea base de seguridad. Esta página la define: al añadir una plataforma nueva, trate estos puntos como requisitos, no como opciones.

Defensa en profundidad

Las capas se apilan bajo el principio de que ninguna basta por sí sola:

Capa Protección
Edge (nginx) TLS, HSTS, rate limit, límite de tamaño del cuerpo
Aplicación (HTTP) Cabeceras de seguridad, allow-list de CORS, CSRF, timeouts
Aplicación (lógica) RBAC, comprobación de permisos, validación de entrada
Base de datos RLS, consultas parametrizadas
Auditoría Registro de auditoría encadenado por hash

El token nunca llega al JS del cliente

El patrón BFF (Backend-for-Frontend) es la base de la seguridad del frontend.

El navegador nunca habla directamente con el backend: solo habla con rutas de Next.js del mismo dominio, y estas hacen de proxy hacia el backend desde el servidor. El token vive en una cookie httpOnly.

El resultado: el XSS deja de ser un vector de robo de tokens. Aunque un atacante logre ejecutar JavaScript, no alcanza el token.

Encima se añade doble protección CSRF: cabecera propia más comprobación de origin.

Cabeceras de seguridad

En todas las respuestas:

Cabecera Propósito
Content-Security-Policy Cierra el vector de ejecución del XSS
Strict-Transport-Security Fuerza HTTPS (HSTS)
Cross-Origin-Opener-Policy Aísla frente a ataques entre ventanas
Cross-Origin-Embedder-Policy Controla los recursos externos
Cross-Origin-Resource-Policy Limita el uso externo de los recursos

El CORS funciona por allow-list — nunca *.

Row-Level Security de Postgres

El aislamiento de los datos de organizaciones y usuarios se aplica a nivel de base de datos, no con una cláusula WHERE en el código de la aplicación.

Por qué: basta un WHERE user_id = ? olvidado en el código para que se filtren datos. La RLS aplica esa comprobación a todas las consultas, al margen de los errores de programación.

Guard de aplicabilidad en el arranque

Al arrancar, la aplicación comprueba que la RLS esté realmente activa. Si falta una policy, o si el usuario de conexión tiene derecho a saltarse la RLS, la aplicación se niega a arrancar.

El motivo es que una RLS desactivada en silencio es el peor caso posible: todo aparenta funcionar con normalidad.

SQL

  • Consultas parametrizadas — sin concatenación de cadenas.
  • Sin ORM — SQL escrito a mano sobre pgx. Cada consulta queda a la vista.

Rate limits y timeouts

Protección Dónde
Rate limit de autenticación (estricto) Rutas /login, /oauth, /auth, /api/auth
Rate limit general de la app (laxo) El resto de rutas
Rate limit de API API públicas del tipo /v1/*
Timeouts del servidor HTTP read · write · idle · header — todos configurados
Límite de tamaño del cuerpo En el edge

Límites estrictos solo en la autenticación

Poner el rate limit estricto de autenticación en todas las rutas hace que los prefetch RSC de Next.js superen el límite y reciban 503. Por eso el límite estricto se aplica solo a las rutas de autenticación, y uno laxo al resto.

Gestión de secretos

  • Cifrado de tokens — los tokens OAuth de terceros (Google Drive, Dropbox, etc.) se guardan cifrados con AES-256-GCM.
  • Claves criptográficas — en HSM; el HSM on-premise y el de la nube se respaldan mutuamente.
  • Secretos de la aplicación — por variables de entorno, nunca en git.

No ponga secretos en el repositorio

Credenciales de servidor, claves de API, client secret, PIN del HSM: nada de esto se escribe jamás en un repositorio, un script o la documentación. Los scripts de despliegue reciben los secretos solo por variables de entorno.

Si un secreto queda expuesto por accidente: (1) rótelo de inmediato, (2) revise los registros de acceso, (3) muévalo a un sistema de gestión de secretos.

Endpoints cerrados en producción

/metrics y /swagger exponen la estructura interna y el listado de endpoints. En producción están protegidos con bearer token.

Registro de auditoría

Un registro encadenado por hash y solo de adición. Cada entrada contiene el hash de la anterior.

Lo que eso significa: ninguna entrada intermedia puede borrarse ni alterarse — la cadena se rompe y la comprobación de integridad falla. Solo lo leen los administradores, y existe una operación aparte para verificar la integridad.

Firma y no repudio

Los actos con consecuencias jurídicas exigen firma con PIN2: la autenticación (PIN1) no basta. Véase Autenticación y autorización para el detalle.

La clave privada de firma está dividida mediante ECDSA de umbral 2-of-2: ninguna de las partes puede firmar por sí sola.

Pruebas

  • Pruebas unitarias — lógica de negocio y comprobaciones de permisos.
  • Pruebas de integración con testcontainers — contra PostgreSQL/Redis reales, que ejercitan la RLS de verdad.
  • Pruebas de golden vector — compatibilidad criptográfica a nivel de protocolo.

Lista de comprobación de seguridad

Antes de que una plataforma nueva salga a producción:

  • [ ] TLS + HSTS activos, certificados que se renuevan automáticamente
  • [ ] Todas las cabeceras de seguridad configuradas (CSP · HSTS · COOP · COEP · CORP)
  • [ ] Allow-list de CORS — sin *
  • [ ] Rate limits: estricto en autenticación, laxo en lo demás
  • [ ] Todos los timeouts del servidor HTTP configurados
  • [ ] RLS activa y guard de arranque funcionando
  • [ ] Todas las consultas parametrizadas
  • [ ] Tokens en cookies httpOnly, sin llegar al JS del cliente
  • [ ] Doble protección CSRF
  • [ ] /metrics y /swagger cerrados
  • [ ] Registro de auditoría escribiéndose, integridad verificable
  • [ ] Secretos por variables de entorno, ausentes del repositorio
  • [ ] Pruebas de integración que ejercitan la RLS de verdad