Secure App Scaffolder
Genera una aplicación segura por diseño compatible con ANSSI, CIS, FBI y OWASP ASVS nivel 2: frontend TypeScript, backend Python, PostgreSQL endurecido.
El diseño, README e interfaz de usuario siguen la skill project-blueprint. Las reglas de seguridad de esta skill tienen prioridad sobre cualquier regla de conveniencia o experiencia de usuario.
Archivos de referencia (leer al generar el artefacto correspondiente)
- reference/docker-compose.yml: compose endurecido con arranque de secretos.
- reference/nginx.conf: proxy inverso con TLS 1.3, PQ híbrido, cabeceras, límites de velocidad.
- reference/security-tests.md: matriz obligatoria de pruebas de seguridad.
Cuándo Usarlo
- Iniciar, construir o diseñar una nueva aplicación o servicio web.
- Solicitudes que mencionen ANSSI, CIS, FBI, OWASP, hardening, rootless, cumplimiento.
- Agregar autenticación, autorización, subidas de archivos, registro de auditoría, funciones de administración, archivos de despliegue o endpoints MCP.
Objetivos de despliegue: Solo Docker y Podman rootless. No generar manifiestos de Kubernetes, Helm u otros orquestadores a menos que el usuario lo solicite explícitamente.
0. Modelo de Amenazas
- Crear
docs/security/threat-model.md(≤ 1 página): activos, límites de confianza, actores, principales riesgos (STRIDE) y el control que mitiga cada uno. Actualizarlo cuando aparezca un nuevo límite de confianza (subida, webhook, LLM, MCP).
1. Contenedores y Entorno de Ejecución
- Rootless: toda imagen termina con un
USERnumérico (ej.USER 10001:10001), incluido el servidor web (nginxinc/nginx-unprivileged, puerto > 1024). - Imágenes mínimas y fijadas: compilaciones multi-etapa; la etapa de ejecución es distroless o slim sin shell, compilador ni gestor de paquetes; dependencias de desarrollo excluidas. Imágenes base fijadas por digest. Última versión estable de Python.
- Hardening:
read_only,tmpfspara rutas de escritura,cap_drop: [ALL],no-new-privileges, perfil seccomp predeterminado en tiempo de ejecución (nuncaunconfined),pids_limit, límites de memoria, healthchecks, volcados de núcleo deshabilitados (ulimits: core: 0). Solo el proxy inverso publica puertos; la red de la base de datos esinternal: true. Nunca montar el socket de Docker/Podman. - Sin subprocesos: no usar
subprocess,os.system,shell=True. Aplicado por: ausencia de shell en la imagen, una regla SAST, y un filtro seccomp en proceso que deniegaexecve/execveatcargado en cada worker después del inicio (una denegación a nivel de contenedor impediría que el propio entrypoint se inicie). - Garantía de primer inicio: en un clon limpio,
docker compose up(tambiéndocker-compose upypodman compose up) funciona a la primera: sin.env, sin paso manual, sin otro requisito que el motor de contenedores. Las imágenes se compilan automáticamente (build:), solo se utilizan funciones de Compose Specification compatibles con Docker Compose v2 y podman-compose, sin rutas de host fuera del repositorio, puertos publicados > 1024, sin límites de CPU (no disponibles en muchas configuraciones rootless con cgroups).make upes un envoltorio ligero sobre el mismo comando. - Sin secretos hardcodeados: un servicio
initde un solo uso genera secretos en un volumen con nombre (0600) consumidos a través de variables*_FILE. Los secretos se leen de archivos, no de variables de entorno, en producción. - Aislado: todo JS/CSS/fuentes/iconos empaquetados; sin CDN, descarga en tiempo de ejecución ni telemetría. Las dependencias provienen de un mirror interno (Nexus, Artifactory, devpi, Verdaccio) al compilar sin conexión.
- Preparado para Vault: una abstracción única de proveedor de secretos (
filepor defecto,vault/sopsen producción). - TLS interno: backend ↔ base de datos sobre TLS; mTLS opcional entre servicios.
2. Cadena de Suministro y Escaneo
- Dependencias bloqueadas: commit de lockfiles;
npm ci,uv sync --frozenopip install --require-hashes..npmrcconignore-scripts=truea menos que un paquete requiera scripts de instalación (lista blanca). - Puerta de pre-compilación:
npm audit --audit-level=highypip-auditfallan la compilación con código de salida > 0. - SAST y secretos: pre-commit con
ruff,bandit/semgrep,eslint(+eslint-plugin-security),gitleaks. - Escaneo de imágenes (
make scan):trivy image(CVEs + secretos + configuraciones incorrectas),trivy configen Dockerfiles y compose,oscap-podman(ooscap-docker) contra el perfil CIS del SO base. - SBOM y firma (
make sbom): SBOM CycloneDX (Trivy o Syft), imágenes firmadas concosign(basado en clave para offline), SBOM adjunto como atestación; el despliegue verifica la firma. - DAST (opcional, recomendado): línea base de OWASP ZAP contra la pila en ejecución en CI.
- Actualizaciones: Renovate/Dependabot (o una revisión offline equivalente) en una cadencia fija.
3. Frontend (TypeScript)
- Ubicación:
/frontendcon su propioDockerfile, compilado como activos estáticos servidos por Nginx sin privilegios. - Código compatible con CSP: sin
<script>en línea, sineval/new Function, sin CSS-in-JS en tiempo de ejecución que inyecte<style>sin nonce. Preferir CSS compilado. Tipos de confianza habilitados (require-trusted-types-for 'script'). - Entrada de confianza cero: esquema Zod tipado por formulario, compartido con tipos de API. Nunca
dangerouslySetInnerHTML/v-htmlen datos no confiables; DOMPurify si el texto enriquecido es inevitable. - Idempotencia: el cliente de API adjunta una
Idempotency-Key(UUIDv4) a cada POST/PUT/PATCH/DELETE, generada una vez por acción de usuario y reutilizada en reintentos. - CSRF: cabecera personalizada (
X-Requested-With) + token CSRF; el backend también verificaOrigin/Sec-Fetch-Site. Lista blanca CORS solo, nunca*con credenciales. - Redirecciones abiertas:
next/returnUrlposterior al inicio de sesión acepta solo rutas relativas que comiencen con un solo/. - Sin secretos en el bundle; sin mapas de origen en producción; sin datos sensibles en
localStorage/sessionStorage.
4. Backend (Python) y Base de Datos
- Validación: cada cuerpo, parámetro de consulta, parámetro de ruta y cabecera validado por Pydantic con longitudes máximas y
extra="forbid"(previene asignación masiva:role,owner_id,is_adminnunca son vinculables desde la entrada). - Límites de recursos: tamaño máximo del cuerpo de la solicitud, profundidad/longitud máxima de JSON, tamaño máximo de página (ej. 100), timeouts del lado del servidor. Las expresiones regulares en la entrada del usuario están acotadas o usan un motor de tiempo lineal (
re2) para evitar ReDoS. - Análisis seguro: sin
pickle,marshal,yaml.load(usaryaml.safe_load),eval. XML mediantedefusedxml. Sin entrada de usuario en fuentes de plantillas (SSTI). Las rutas de archivo se resuelven y verifican contra un directorio base (path traversal). - Almacén de idempotencia:
(user_id, key) -> request_hash, status, response, TTL de 24 h. La misma clave + el mismo hash devuelve la respuesta almacenada; un hash diferente devuelve422. Esto evita duplicados; la protección contra repetición proviene de TLS, tokens CSRF y sesiones cortas. - SQL: solo ORM o consultas parametrizadas; identificadores dinámicos (
ORDER BY, nombres de columna) a través de una lista blanca. - Cifrado a nivel de columna: PII cifrado en la aplicación con AES-256-GCM, cifrado de sobre (DEK por registro envuelto por una clave maestra del proveedor de secretos), columna
key_versionpara rotación, índice ciego HMAC-SHA256 para campos buscables. La clave maestra nunca se almacena en la base de datos ni en las copias de seguridad. - Hardening de base de datos: PostgreSQL mínimo,
scram-sha-256, TLS, dos roles (propietario de migraciones, runtime solo DML), sin superusuario desde la aplicación, migraciones Alembic,statement_timeouten el rol de runtime. - Consola SQL (si existe): rol de solo lectura, un solo
SELECT,statement_timeout, límite de filas, configuración bloqueada. - Criptografía y post-cuántica: AES-256-GCM en reposo es resistente a cuántica. La preparación PQ apunta a intercambio de claves y firmas: TLS híbrido
X25519MLKEM768en el proxy; ML-KEM/ML-DSA (FIPS 203/204) solo donde la biblioteca los soporta. Valores aleatorios desecrets/crypto.getRandomValues. Nunca implementar primitivas criptográficas. - Solicitudes salientes (SSRF): cualquier URL configurable desde la interfaz de usuario (webhooks, syslog, LLM, OIDC) se valida: solo
https(a menos que haya una lista blanca explícita), la IP resuelta se rechaza si es loopback/link-local/metadata (169.254.0.0/16,fd00:ec2::254) o privada a menos que esté en lista blanca, se verifica de nuevo después de la resolución DNS (DNS rebinding), sin redirecciones entre hosts, timeouts estrictos. - Webhooks salientes: firmados con HMAC-SHA256 (
X-Signature+ timestamp) para que los receptores puedan verificarlos. - Correo electrónico: los valores de cabecera se despojan de CR/LF; SMTPS con verificación de certificado.
- Exportaciones: las celdas CSV/XLSX que comienzan con
=,+,-,@, tabulador o CR se prefijan con'(inyección de fórmulas). - Límite de velocidad: inicio de sesión, restablecimiento de contraseña, verificación MFA, claves de API, exportaciones, subidas y endpoints costosos.
- Respuestas:
Cache-Control: no-storeen respuestas de API autenticadas. Mensajes de error genéricos con unrequest_id; trazas de pila solo en registros. Interfaz de OpenAPI deshabilitada o solo para administradores en producción.
5. Autorización
- Denegar por defecto: cada ruta declara su permiso requerido; una ruta sin declaración falla al inicio o en las pruebas.
- RBAC con roles mapeados a permisos (no roles verificados directamente en el código).
- Verificaciones a nivel de objeto (IDOR/BOLA): verificación de propiedad o inquilino en la capa de repositorio para cada lectura/escritura por ID. El acceso no autorizado a un objeto existente devuelve
404. - Verificaciones a nivel de función: rutas de administrador bajo
/api/v1/admin/*protegidas por una única dependencia, nunca ocultando solo la interfaz de usuario. - Acciones sensibles (cambios de rol, creación de claves, exportaciones, eliminación de usuarios) requieren reautenticación reciente; aprobación opcional de cuatro ojos para la escalada de roles a administrador.
6. Subidas de Archivos (si las hay)
- Límite de tamaño a nivel de proxy y aplicación; lista blanca de extensiones y verificación de magic bytes.
- Almacenados fuera de la raíz web (o almacenamiento de objetos), nombres de archivo aleatorios, servidos con
Content-Disposition: attachmentyX-Content-Type-Options: nosniff. - Las imágenes se recodifican (elimina EXIF y poliglotas); los archivos comprimidos se verifican en busca de bombas y path traversal; antivirus offline opcional (ClamAV).
- Las subidas SVG y HTML se rechazan a menos que se desinfecten y se sirvan desde un origen aislado.
7. Registro, Auditoría y Administración
- Registros estructurados: JSON, niveles DEBUG/INFO/WARN/ERROR/CRITICAL,
request_iden todas partes, marcas de tiempo UTC, CR/LF eliminados de los valores de usuario. Contraseñas, tokens, claves, ID de sesión nunca se registran. - Syslog remoto: RFC 5424 sobre TLS (RFC 5425) con búfer local acotado; host, puerto, TLS, CA configurables desde la interfaz de administración. Sin contenedor rsyslog.
- Notificaciones de error: SMTPS y webhooks configurables desde la interfaz de administración, validados contra SSRF, botón "Enviar prueba", limitados.
- Enmascaramiento de PII: middleware activable desde la interfaz de administración.
- Registro de auditoría a prueba de manipulaciones: tabla de solo añadir (el rol de runtime tiene solo
INSERT/SELECT), cada fila encadenada con el hash de la fila anterior, reenviado a syslog. Cubre inicios de sesión, fallos, cambios MFA, cambios de rol, cambios de configuración, exportaciones, claves de API, accesos a honeytokens; registra usuario, IP, agente de usuario, hora UTC y valores antes/después. - Panel de administración: estadísticas de uso, errores, alertas de honeytokens, IPs bloqueadas.
- Higiene programada: deshabilitar cuentas inactivas, purgar tokens/sesiones/claves de idempotencia caducados, copias de seguridad cifradas diarias (clave separada de la copia de seguridad), política de retención y un procedimiento de restauración probado (
make restore-test). - Datos personales (GDPR): períodos de retención por tipo de dato, exportación y eliminación de datos de usuario, trabajos de purga.
8. Autenticación, Identidad y Defensa Activa
- Contraseñas: Argon2id (valores predeterminados argon2-cffi / RFC 9106, mínimo m=19 MiB, t=2, p=1), rehash al iniciar sesión cuando los parámetros cambian. Política según NIST SP 800-63B: ≥ 12 caracteres, máximo ≥ 64, sin reglas de composición, rechazada si está en una lista de contraseñas vulneradas/comunes incluida.
- Inicio de sesión: respuesta y tiempo idénticos para usuarios desconocidos, retardos progresivos + limitación por cuenta y por IP (evitar bloqueo duro que permita DoS).
- Restablecimiento de contraseña: token aleatorio de un solo uso almacenado con hash, caducidad de 30 min, misma respuesta si la cuenta existe o no, todas las sesiones revocadas después del restablecimiento.
- Sesiones: del lado del servidor, cookie
__Host-session(HttpOnly; Secure; SameSite=Lax; Path=/), ID rotado al iniciar sesión y cambiar privilegios, los usuarios pueden listar y revocar sus sesiones activas. Sin JWT en almacenamiento del navegador; si se usan JWT servicio a servicio: algoritmo fijado,nonerechazado,aud/iss/expverificados, vida útil corta. - Sesiones de administrador: 1 h inactiva, 8 h absoluta, reautenticación para acciones destructivas.
- MFA: TOTP (códigos de recuperación con hash, rechazo de repetición del mismo código) y WebAuthn/Passkeys. MFA obligatorio para cuentas de administrador.
- Detección de contexto: los inicios de sesión de administrador desde IP/dispositivo desconocido activan una notificación "Nuevo inicio de sesión" y restringen los derechos destructivos hasta la confirmación MFA.
- Administrador de arranque: contraseña aleatoria generada en el primer inicio, legible una vez mediante
make admin-password, restablecimiento forzado + inscripción MFA en el primer inicio de sesión. - Cuenta de emergencia (opcional): administrador local utilizable cuando SSO está caído, deshabilitada por defecto, cada uso genera una alerta crítica.
- SSO: flujo de código OIDC + PKCE,
stateynoncevalidados, firma/aud/issdel token ID verificados; LDAPS o StartTLS con verificación de certificado, valores de filtro LDAP escapados (inyección LDAP). Grupos de directorio mapeados a roles. - Configuración SSO, dos fuentes equivalentes: cada parámetro de OIDC y LDAP(S) (indicador de habilitación, URL del emisor/servidor, ID de cliente, ámbitos, DN de enlace, DN base, filtros de usuario/grupo, paquete CA, mapeo grupo a rol, aprovisionamiento automático) se puede configurar desde la interfaz de administración o desde variables de entorno (
BACKEND_OIDC_*,BACKEND_LDAP_*).- Los secretos (
client_secret, contraseña de enlace) provienen de variables*_FILEo del proveedor de secretos, nunca valores de entorno sin formato en producción; en la interfaz de usuario son de solo escritura (••••last4). - Precedencia: una configuración definida por entorno gana y se muestra solo lectura en la interfaz de administración con una etiqueta "Gestionado por entorno"; todo lo demás es editable y se almacena cifrado en la base de datos.
- Misma validación para ambas fuentes (esquema Pydantic compartido por el cargador de entorno y la API de administración); la configuración de entorno no válida falla al inicio con un error claro, la entrada de interfaz de usuario no válida se rechaza antes de guardar.
- La interfaz de administración tiene una acción "Probar conexión" (descubrimiento OIDC + obtención JWKS, enlace LDAP + búsqueda de grupo de muestra) y cada cambio se audita.
- Cada...
- Los secretos (