Cuándo usar: léela ANTES de tocar cualquier cosa sensible: flujos de autenticación o autorización, manejo de datos de usuario o PII, endpoints públicos o expuestos a internet, formularios y parámetros que reciben entrada externa, consultas a base de datos con datos del usuario, manejo de secretos/credenciales/tokens, cookies y sesiones, subida de archivos, integraciones con terceros, o cualquier código que decida "¿este usuario puede hacer esto?". Si dudas de si aplica, aplica.
La seguridad no es una feature que se agrega al final: es una propiedad transversal del diseño. Un sistema seguro no depende de que "nadie encuentre el fallo", sino de que el fallo, aunque exista, no comprometa todo. Este skill tiene enfoque defensivo: proteger el sistema, no atacarlo. El objetivo es que entiendas el PORQUÉ de cada regla, porque una regla memorizada sin entender se rompe en el primer caso que no la contempla.
1. Principios fundamentales
Estos cinco principios son la base. Cada regla concreta más abajo es una consecuencia de alguno de ellos.
Defensa en profundidad (defense in depth): nunca dependas de una sola barrera. Si el WAF falla, la validación de entrada debe atrapar el ataque; si esa falla, la consulta parametrizada; si esa falla, los permisos mínimos de la BD limitan el daño. Capas independientes. Un atacante debe romper TODAS, no una.
Mínimo privilegio (least privilege): cada componente, usuario, token o proceso recibe solo los permisos que necesita para su tarea, ni uno más. El servicio que lee reportes no necesita DROP TABLE. El token de un widget de frontend no necesita scope de admin. Menos privilegio = menos superficie de daño cuando algo se compromete.
Secure by default: el estado por defecto debe ser el seguro. Un endpoint nuevo debe estar cerrado hasta que explícitamente lo abras, no abierto hasta que recuerdes cerrarlo. Un permiso ausente se interpreta como "denegar", no como "permitir". La configuración de fábrica no debe requerir "endurecerla" para ser segura.
No confiar en la entrada (never trust input): TODO dato que cruza una frontera de confianza es hostil hasta que se demuestre lo contrario: parámetros HTTP, headers, cookies, cuerpos JSON, archivos subidos, respuestas de APIs de terceros, incluso datos que vienen de tu propia BD si originalmente los puso un usuario. La validación ocurre en el servidor, siempre. El cliente valida por UX, no por seguridad.
Fail securely (fallar de forma segura): cuando algo sale mal, el sistema debe caer hacia el estado seguro, no hacia el abierto. Si la verificación de permisos lanza una excepción, el resultado es DENEGAR, no PERMITIR. Un error nunca debe convertirse accidentalmente en un bypass. Compara: if (tienePermiso()) permitir() deja pasar si tienePermiso() explota y alguien lo captura mal; el diseño correcto deniega por defecto y solo permite en el camino explícitamente autorizado.
2. Reglas de oro
Haz
Evita
Validar y autorizar SIEMPRE en el servidor
Confiar en validaciones o checks del cliente
Consultas parametrizadas / ORM con bindings
Concatenar entrada del usuario en SQL/comandos
Hashear contraseñas con bcrypt / argon2 / scrypt
MD5, SHA-1, SHA-256 "a secas" o texto plano
Codificar la salida según el contexto (HTML, JS, URL)
Insertar datos del usuario crudos en el DOM
Secretos en gestor de secretos / variables de entorno
Secretos hardcodeados o commiteados al repo
Allowlist (lista de lo permitido)
Denylist (lista de lo prohibido)
HTTPS/TLS en todo, HSTS activo
HTTP plano, TLS opcional o downgradeable
Verificar autorización por objeto en cada acceso
Asumir que "solo la UI muestra sus datos"
Mensajes de error genéricos al cliente
Devolver stack traces, versiones o SQL al cliente
Rate limiting en auth y endpoints costosos
Login/reset sin límite de intentos
Rotar y revocar credenciales y tokens
Tokens eternos sin expiración ni revocación
Dependencias actualizadas y escaneadas
Librerías con CVEs conocidos "porque funciona"
3. OWASP Top 10 (referencia 2021, vigente)
El estándar de facto para priorizar riesgos en aplicaciones web. Conócelo de memoria a nivel de qué es y cómo se mitiga.
A01 – Broken Access Control (control de acceso roto): el usuario accede a datos o acciones que no le corresponden (ver el pedido de otro, escalar a admin). Mitigar: denegar por defecto, verificar autorización por objeto en el servidor en CADA request, no exponer IDs adivinables sin check de propiedad. Ver §8.
A02 – Cryptographic Failures (fallos criptográficos): datos sensibles sin cifrar o con cripto débil (contraseñas en SHA plano, TLS opcional, PII en claro). Mitigar: TLS obligatorio, cifrado en reposo, algoritmos actuales, hashing lento para contraseñas. Ver §7 y §14.
A03 – Injection (inyección): SQL, NoSQL, comandos de SO, LDAP donde entrada del usuario se interpreta como código. Mitigar: consultas parametrizadas, ORM, validación por allowlist, nunca concatenar. Ver §4.
A04 – Insecure Design (diseño inseguro): el fallo está en la arquitectura, no en un bug puntual (flujo de recuperación de cuenta sin verificación, ausencia de límites de negocio). Mitigar: threat modeling, patrones seguros desde el diseño, historias de abuso además de historias de usuario.
A05 – Security Misconfiguration (configuración insegura): defaults inseguros, features de debug en producción, permisos abiertos, cabeceras faltantes. Mitigar: hardening por defecto, deshabilitar lo no usado, cabeceras de seguridad, revisar config por entorno. Ver §13.
A06 – Vulnerable and Outdated Components (componentes vulnerables): dependencias con CVEs conocidos. Mitigar: inventario de dependencias, escaneo continuo, actualizar, lockfiles. Ver §15.
A07 – Identification and Authentication Failures (fallos de autenticación): login débil, sesiones mal gestionadas, credenciales por defecto, sin MFA. Mitigar: hashing fuerte, MFA, gestión de sesión robusta, rate limiting. Ver §6 y §9.
A08 – Software and Data Integrity Failures (fallos de integridad): deserialización insegura, actualizaciones o dependencias sin verificar firma, CI/CD comprometido. Mitigar: verificar integridad/firmas, no deserializar datos no confiables, proteger el pipeline (supply chain). Ver §15.
A09 – Security Logging and Monitoring Failures (fallos de logging y monitoreo): ataques que pasan inadvertidos por falta de registro o alertas. Mitigar: logging de eventos de seguridad, monitoreo y alertas, sin loggear secretos. Ver §16.
A10 – Server-Side Request Forgery (SSRF): el servidor hace peticiones a URLs controladas por el atacante (acceso a metadata interna, red interna). Mitigar: allowlist de destinos, bloquear rangos internos/loopback, no reenviar URLs crudas del usuario.
4. Inyección (SQL / NoSQL / comandos)
La inyección ocurre cuando datos se interpretan como código. La causa raíz es mezclar datos y código en la misma cadena. La solución no es "escapar mejor": es separar estructuralmente datos de instrucciones.
Regla absoluta: nunca concatenes entrada del usuario en una consulta o comando.
-- ❌ VULNERABLE: la entrada se convierte en código
query = "SELECT * FROM users WHERE email = '" + email + "'"
-- entrada: ' OR '1'='1 → devuelve todos los usuarios
-- ✅ SEGURO: consulta parametrizada, el driver separa datos de código
query = "SELECT * FROM users WHERE email = ?"
db.execute(query, [email])
SQL: usa consultas parametrizadas / prepared statements SIEMPRE, o un ORM que use bindings por debajo. El placeholder (?, $1, :email) garantiza que el valor jamás se interprete como estructura.
NoSQL (p. ej. MongoDB): también es inyectable. Un { "$gt": "" } inyectado en un campo de contraseña puede saltarse el login. Valida tipos, rechaza operadores en entrada, usa el driver correctamente.
Comandos de SO: evita invocar shell con entrada del usuario. Si es inevitable, usa APIs que reciban argumentos como array (no una cadena de shell) y valida contra allowlist. Nunca exec("convert " + filename).
Cuando la parametrización no cubre (nombres de tabla/columna dinámicos, ORDER BY): usa allowlist — compara la entrada contra un conjunto fijo de valores válidos, nunca la insertes directa.
Enlace: al diseñar el acceso a datos, coordina con database-design para modelos y permisos de BD con mínimo privilegio.
5. Cross-Site Scripting (XSS)
XSS ejecuta JavaScript del atacante en el navegador de la víctima. Causa raíz: datos del usuario tratados como marcado/código en la salida. La defensa central es codificar la salida según el contexto.
Reflejado: la entrada vuelve inmediatamente en la respuesta (búsqueda que repite el término sin codificar).
Almacenado: la carga se guarda (comentario, perfil) y ataca a todos los que lo ven. El más peligroso.
DOM-based: JS del propio sitio escribe entrada no confiable en el DOM (innerHTML, document.write).
Mitigaciones, en capas:
Codificación de salida contextual: codifica según DÓNDE se inserta el dato — HTML body, atributo, dentro de <script>, URL. No es lo mismo. Usa las utilidades del framework (React/Angular/Vue escapan por defecto; respétalas).
Nunca uses innerHTML / dangerouslySetInnerHTML / v-html con datos del usuario. Usa textContent o binding seguro. Si DEBES renderizar HTML del usuario, sanitiza con una librería robusta (p. ej. DOMPurify) — nunca a mano con regex.
Content Security Policy (CSP): cabecera que restringe de dónde se cargan scripts. Una CSP estricta (sin unsafe-inline) convierte muchos XSS en inofensivos aunque la carga llegue. Es tu red de seguridad, no tu primera línea.
Cookies con HttpOnly: evita que JS lea la cookie de sesión, limitando el robo de sesión vía XSS.
Un sitio malicioso hace que el navegador de la víctima envíe una petición autenticada a TU sitio (aprovechando su cookie de sesión) sin que ella lo sepa (transferir dinero, cambiar email).
Mitigaciones:
Tokens anti-CSRF: token impredecible por sesión/formulario que el servidor emite y verifica en cada petición que cambia estado. El sitio atacante no puede leerlo (same-origin), así que no puede falsificar la petición.
Cookies SameSite:SameSite=Lax (buen default) o Strict impide que la cookie se envíe en peticiones cross-site, cortando el vector de raíz. Combínalo con tokens; no dependas de uno solo.
Verifica el método: las operaciones que cambian estado nunca por GET. GET es seguro/idempotente por contrato; mutaciones van por POST/PUT/PATCH/DELETE.
Para APIs con tokens en header (no cookies), CSRF clásico no aplica igual, pero valida Origin/Referer en flujos sensibles.
7. Autenticación (¿quién eres?)
Hashing de contraseñas: usa un algoritmo lento y con sal: argon2 (preferido), bcrypt o scrypt. Están diseñados para ser costosos y resistir fuerza bruta con GPU. NUNCA MD5, SHA-1, SHA-256/512 planos: son rápidos, y "rápido" es exactamente lo que un atacante quiere para probar millones de hashes.
Salting: cada contraseña con una sal única y aleatoria (bcrypt/argon2 la manejan internamente). La sal impide precomputar (rainbow tables) y hace que dos usuarios con la misma contraseña tengan hashes distintos.
Nunca guardes la contraseña en claro ni cifrada de forma reversible. El hashing es unidireccional a propósito: no necesitas recuperarla, solo verificarla.
Políticas sensatas: longitud mínima razonable (favorece frases largas sobre reglas de complejidad crípticas), compara contra listas de contraseñas filtradas conocidas, no fuerces rotación periódica arbitraria (empeora la higiene).
MFA (autenticación multifactor): ofrécela y exígela para cuentas privilegiadas. Algo que sabes + algo que tienes. Reduce drásticamente el impacto de credenciales robadas.
Comparación en tiempo constante al verificar tokens/OTP para evitar timing attacks.
Enumeración de usuarios: mensajes de login/registro/reset genéricos ("credenciales inválidas"), sin revelar si el email existe. Ver §17.
8. Autorización (¿qué puedes hacer?)
Authn ≠ Authz. Autenticación es quién eres; autorización es qué se te permite. Estar logueado (authn) no implica poder ver el recurso X (authz). Se verifican por separado, y ambas en el servidor, siempre.
Control de acceso a nivel de objeto (IDOR): el fallo más común. Si /api/orders/1234 devuelve un pedido, verifica que ese pedido pertenece al usuario autenticado, no solo que el usuario esté logueado. Nunca asumas que "como la UI solo le muestra sus IDs, no probará otros". Un atacante cambia el ID a mano en segundos.
RBAC (por roles): permisos agrupados en roles (admin, editor, viewer). Simple y escalable para la mayoría de casos.
ABAC (por atributos): decisiones según atributos del usuario, recurso y contexto (departamento, hora, ubicación). Más granular, más complejo. Úsalo cuando RBAC se queda corto.
Deny by default: sin regla explícita que permita → denegar.
Verifica en cada capa relevante, no solo en el gateway. Un endpoint interno también autoriza.
Enlace: al definir endpoints y su modelo de permisos, aplica esto junto con api-design.
9. Sesiones y tokens
Sesiones (server-side):
ID de sesión aleatorio, largo, impredecible. Cookie con HttpOnly, Secure, SameSite.
Regenera el ID de sesión tras el login (previene session fixation).
Expiración por inactividad y absoluta. Invalida la sesión en el servidor al cerrar sesión (no basta borrar la cookie).
JWT — úsalo entendiendo sus riesgos:
alg: none: rechaza SIEMPRE tokens sin firma. Fija el algoritmo esperado en el servidor; no dejes que el token dicte su propio algoritmo (ataque clásico de confusión de algoritmo, p. ej. RS256→HS256).
No guardes datos sensibles en el payload: un JWT va firmado pero no cifrado; cualquiera lo decodifica en base64 y lee su contenido. Nada de PII, contraseñas ni secretos ahí.
Expiración corta (exp): los JWT son difíciles de revocar porque son autocontenidos. Compénsalo con vida corta + refresh tokens rotables y revocables.
Revocación: para logout real o cuentas comprometidas necesitas una estrategia (lista de revocación, versión de token en BD, o sesiones server-side). No confíes solo en "el token expira eventualmente".
Almacenamiento en el cliente: preferible cookie HttpOnly+Secure sobre localStorage (este último es legible por cualquier XSS).
10. Gestión de secretos
Un secreto en el repositorio es un secreto comprometido — asume que ya se filtró.
NUNCA commitees claves, tokens, contraseñas, cadenas de conexión ni certificados privados. Ni en código, ni en config, ni en tests, ni en el historial.
Usa variables de entorno o, mejor, un gestor de secretos (Vault, AWS Secrets Manager, GCP Secret Manager, etc.) con acceso auditado y mínimo privilegio.
.gitignore para .env y archivos de credenciales; provee un .env.example sin valores reales.
Rota los secretos periódicamente y de inmediato ante cualquier sospecha de exposición.
Si un secreto llegó al repo: rotarlo es lo primero (invalidar el viejo). Borrarlo del historial es secundario y no sustituye la rotación — el valor ya pudo ser clonado. Coordina esto con git-workflow para limpieza de historial y prevención (hooks/escáneres de secretos en pre-commit).
Escaneo automático de secretos en CI y pre-commit para atraparlos antes del push.
11. Validación de entrada y saneamiento de salida
Dos operaciones distintas, ambas necesarias:
Validación de entrada (al recibir): ¿este dato tiene la forma esperada? Tipo, rango, longitud, formato, pertenencia a un conjunto. Allowlist siempre que puedas: define lo que ES válido y rechaza el resto. Una denylist ("bloquea <script>") siempre olvida un caso; una allowlist ("solo dígitos") no.
Saneamiento/codificación de salida (al emitir): transforma el dato para que sea seguro en su destino (HTML, SQL, shell, log, JSON). El MISMO dato se codifica distinto según a dónde va.
Clave: validas al entrar, codificas al salir. No confundas: validar no hace segura la salida, y codificar no valida la lógica de negocio.
Entrada → validar (¿es un email bien formado? ¿el monto es > 0?)
Proceso → tratar como dato, nunca como código
Salida → codificar según contexto (HTML-encode al render, param al SQL)
Valida en el servidor aunque el cliente ya valide (el cliente es cosmético).
Rechaza temprano y explícito; no "arregles" silenciosamente entrada malformada.
12. Transporte y datos
HTTPS/TLS obligatorio en todo el tráfico, sin excepciones ni "solo en login". El tráfico en claro es interceptable y modificable.
HSTS (Strict-Transport-Security): obliga al navegador a usar HTTPS y previene downgrade a HTTP. Actívalo con max-age largo.
Cifrado en reposo: datos sensibles y PII cifrados en disco/BD/backups. Gestiona las claves aparte de los datos.
PII y minimización de datos: recolecta solo lo que necesitas, guárdalo el mínimo tiempo, restringe quién accede. El dato que no tienes no se puede filtrar. Considera anonimización/seudonimización cuando el caso de uso lo permita.
Datos sensibles fuera de URLs (quedan en logs, historial, referrers). Van en el cuerpo, no en query strings.
13. Cabeceras de seguridad
Configúralas por defecto en todas las respuestas:
Content-Security-Policy: controla orígenes de scripts/estilos/recursos. La defensa más potente contra XSS. Empieza restrictiva y afloja lo justo; evita unsafe-inline.
X-Content-Type-Options: nosniff: impide que el navegador adivine el MIME type y ejecute algo como script por error.
X-Frame-Options: DENY (o CSP frame-ancestors): previene clickjacking al no permitir embeber tu sitio en iframes.
Referrer-Policy (p. ej. strict-origin-when-cross-origin): limita qué URL se filtra en el header Referer hacia terceros.
Permissions-Policy: restringe APIs del navegador (cámara, geolocalización) que tu app no usa.
14. Criptografía (usar, no inventar)
No implementes cripto propia. Usa librerías establecidas y revisadas. La cripto casera falla en formas sutiles e invisibles hasta que es tarde.
Algoritmos actuales y modos correctos (AES-GCM para cifrado autenticado; evita ECB y modos sin autenticación).
Aleatoriedad criptográficamente segura (CSPRNG) para tokens, sales, IDs de sesión — nunca Math.random() ni PRNGs de propósito general.
Gestiona el ciclo de vida de las claves: generación, almacenamiento seguro, rotación, revocación.
Para contraseñas: hashing lento (§7). Para datos que necesitas recuperar: cifrado simétrico autenticado. Son problemas distintos con herramientas distintas.
15. Dependencias y supply chain
Tu código es tan seguro como la librería más débil que importas.
Escaneo continuo de vulnerabilidades (Dependabot, npm audit, pip-audit, Snyk, etc.) en CI. Trata los CVEs como bugs bloqueantes según severidad.
Actualiza con regularidad; no dejes que las dependencias envejezcan hasta acumular deuda de seguridad.
Lockfiles (package-lock.json, poetry.lock, go.sum) commiteados: builds reproducibles y protección contra sustitución de versiones.
Minimiza dependencias: cada paquete es superficie de ataque y riesgo de código malicioso. ¿Realmente necesitas esa librería para tres líneas?
Verifica integridad (hashes/firmas) de artefactos y del pipeline de build. Protege credenciales de CI/CD: un pipeline comprometido inyecta en todo lo que despliega.
16. Logging seguro
El logging es doble filo: esencial para auditoría, peligroso si registra lo que no debe.
NUNCA loggees: contraseñas, tokens, claves de API, cookies de sesión, PII sensible, números completos de tarjeta, contenido de secretos. Ni siquiera "temporalmente para debug" — esos logs persisten y se filtran.
SÍ registra para auditoría: intentos de login (éxito y fallo), cambios de permisos, accesos a datos sensibles, operaciones administrativas, errores de seguridad. Con quién, qué, cuándo y desde dónde — sin el contenido secreto.
Enmascara/redacta datos sensibles antes de escribir (p. ej. ****1234).
Protege los logs mismos: acceso restringido, retención definida, sin exponerlos públicamente.
Enlace: para el diseño de logging estructurado, correlación, niveles y qué es auditable, apóyate en error-handling-observability.
17. Manejo de errores y menor exposición
No filtres internals al cliente: stack traces, mensajes de la BD, rutas de archivos, nombres de frameworks o versiones. Ayudan al atacante a mapear el sistema. Al cliente: mensaje genérico + un ID de correlación. El detalle va al log interno.
Mensajes uniformes en flujos sensibles (login, reset, registro): no reveles si el email existe, si la contraseña era casi correcta, etc. Evita la enumeración.
Menor exposición en respuestas de API: devuelve solo los campos necesarios. Nada de SELECT * serializado crudo que arrastre password_hash, flags internos o campos de otros usuarios. Define DTOs de salida explícitos (allowlist de campos), no listas de exclusión.
Fail securely (§1): un error en la verificación de permisos deniega, no permite.
18. Rate limiting y anti-abuso
Rate limiting en autenticación, reset de contraseña, verificación de OTP y endpoints costosos. Frena fuerza bruta y credential stuffing.
Backoff / bloqueo temporal tras varios intentos fallidos, con cuidado de no habilitar un DoS por bloqueo (prefiere throttling progresivo + CAPTCHA sobre lockout permanente).
Anti-enumeración: respuestas y tiempos uniformes para no revelar existencia de recursos/usuarios (§17).
Límites de negocio: además de límites técnicos, pon topes lógicos (máximo de transferencias, de creación de recursos) para contener abuso automatizado.
Anti-patrones comunes
"Lo valido en el frontend, con eso basta." — El cliente es inspeccionable y modificable. Toda validación de seguridad es del lado servidor.
Concatenar entrada en SQL/comandos "porque el ORM es lento aquí".
md5(password) o sha256(password) para guardar contraseñas.
Comprobar if (user.isLoggedIn) y asumir que eso autoriza el acceso al objeto (falta el check de ownership → IDOR).
Guardar el JWT en localStorage y meter datos sensibles en su payload.
Secretos hardcodeados "temporalmente" que terminan en el historial de git.
Denylist de caracteres "peligrosos" en lugar de allowlist de lo válido.
Devolver el stack trace al cliente en producción para "facilitar el debug".
Desactivar la verificación de certificados TLS (verify=False) para que "funcione ya".
Math.random() para generar tokens o IDs de sesión.
Loggear el request completo (con Authorization header y body) "para debug".
Confiar en Referer/Origin como ÚNICA defensa CSRF sin tokens ni SameSite.
Endpoint nuevo abierto por defecto "porque todavía no configuré permisos".
Checklist de seguridad antes de exponer
Toda entrada del usuario se valida en el servidor (allowlist)
Consultas parametrizadas / ORM; cero concatenación en SQL/NoSQL/shell
Salida codificada según contexto; sin innerHTML con datos de usuario
Autenticación con hashing fuerte (argon2/bcrypt/scrypt) + sal
Autorización verificada en el servidor y por objeto (sin IDOR)
Sesiones/tokens: expiración, revocación, cookies HttpOnly+Secure+SameSite
JWT: algoritmo fijado, alg:none rechazado, sin datos sensibles en el payload
Sin secretos en el repo; en gestor de secretos o variables de entorno
HTTPS/TLS obligatorio y HSTS activo
Cabeceras de seguridad configuradas (CSP, nosniff, X-Frame-Options, Referrer-Policy)
CSRF cubierto (tokens + SameSite) en operaciones que cambian estado
Rate limiting en login, reset y endpoints costosos
Dependencias escaneadas, actualizadas y con lockfile commiteado
Logs sin secretos/PII; eventos de seguridad auditados
Errores genéricos al cliente; sin stack traces ni versiones expuestas
Respuestas de API con solo los campos necesarios (DTO de salida)
Cifrado en reposo para datos sensibles; PII minimizada
Fail securely verificado: los errores deniegan, no permiten
Skills relacionados
api-design — modelado de endpoints, contratos y permisos por recurso.
error-handling-observability — logging estructurado, correlación y manejo de errores sin fuga de internals.
database-design — modelo de datos, permisos de BD con mínimo privilegio, cifrado en reposo.
git-workflow — prevención y limpieza de secretos en el historial, hooks y escáneres en pre-commit.
OWASP API Security Top 10 — riesgos específicos de APIs.
CWE Top 25 — debilidades de software más peligrosas.
NIST SP 800-63B — guía moderna de contraseñas y autenticación.
1---2name: security3description: Seguridad aplicada: OWASP, autenticación/autorización, secretos, validación, defensa en profundidad.4---56# Seguridad Aplicada78> **Cuándo usar:** léela ANTES de tocar cualquier cosa sensible: flujos de autenticación o autorización, manejo de datos de usuario o PII, endpoints públicos o expuestos a internet, formularios y parámetros que reciben entrada externa, consultas a base de datos con datos del usuario, manejo de secretos/credenciales/tokens, cookies y sesiones, subida de archivos, integraciones con terceros, o cualquier código que decida "¿este usuario puede hacer esto?". Si dudas de si aplica, aplica.910La seguridad no es una feature que se agrega al final: es una propiedad transversal del diseño. Un sistema seguro no depende de que "nadie encuentre el fallo", sino de que el fallo, aunque exista, no comprometa todo. Este skill tiene enfoque **defensivo**: proteger el sistema, no atacarlo. El objetivo es que entiendas el PORQUÉ de cada regla, porque una regla memorizada sin entender se rompe en el primer caso que no la contempla.1112---1314## 1. Principios fundamentales1516Estos cinco principios son la base. Cada regla concreta más abajo es una consecuencia de alguno de ellos.1718- **Defensa en profundidad (defense in depth):** nunca dependas de una sola barrera. Si el WAF falla, la validación de entrada debe atrapar el ataque; si esa falla, la consulta parametrizada; si esa falla, los permisos mínimos de la BD limitan el daño. Capas independientes. Un atacante debe romper TODAS, no una.19- **Mínimo privilegio (least privilege):** cada componente, usuario, token o proceso recibe solo los permisos que necesita para su tarea, ni uno más. El servicio que lee reportes no necesita `DROP TABLE`. El token de un widget de frontend no necesita scope de admin. Menos privilegio = menos superficie de daño cuando algo se compromete.20- **Secure by default:** el estado por defecto debe ser el seguro. Un endpoint nuevo debe estar cerrado hasta que explícitamente lo abras, no abierto hasta que recuerdes cerrarlo. Un permiso ausente se interpreta como "denegar", no como "permitir". La configuración de fábrica no debe requerir "endurecerla" para ser segura.21- **No confiar en la entrada (never trust input):** TODO dato que cruza una frontera de confianza es hostil hasta que se demuestre lo contrario: parámetros HTTP, headers, cookies, cuerpos JSON, archivos subidos, respuestas de APIs de terceros, incluso datos que vienen de tu propia BD si originalmente los puso un usuario. La validación ocurre en el **servidor**, siempre. El cliente valida por UX, no por seguridad.22- **Fail securely (fallar de forma segura):** cuando algo sale mal, el sistema debe caer hacia el estado seguro, no hacia el abierto. Si la verificación de permisos lanza una excepción, el resultado es DENEGAR, no PERMITIR. Un error nunca debe convertirse accidentalmente en un bypass. Compara: `if (tienePermiso()) permitir()` deja pasar si `tienePermiso()` explota y alguien lo captura mal; el diseño correcto deniega por defecto y solo permite en el camino explícitamente autorizado.2324---2526## 2. Reglas de oro2728| Haz | Evita |29| --- | --- |30| Validar y autorizar SIEMPRE en el servidor | Confiar en validaciones o checks del cliente |31| Consultas parametrizadas / ORM con bindings | Concatenar entrada del usuario en SQL/comandos |32| Hashear contraseñas con bcrypt / argon2 / scrypt | MD5, SHA-1, SHA-256 "a secas" o texto plano |33| Codificar la salida según el contexto (HTML, JS, URL) | Insertar datos del usuario crudos en el DOM |34| Secretos en gestor de secretos / variables de entorno | Secretos hardcodeados o commiteados al repo |35| Allowlist (lista de lo permitido) | Denylist (lista de lo prohibido) |36| HTTPS/TLS en todo, HSTS activo | HTTP plano, TLS opcional o downgradeable |37| Verificar autorización por objeto en cada acceso | Asumir que "solo la UI muestra sus datos" |38| Mensajes de error genéricos al cliente | Devolver stack traces, versiones o SQL al cliente |39| Rate limiting en auth y endpoints costosos | Login/reset sin límite de intentos |40| Rotar y revocar credenciales y tokens | Tokens eternos sin expiración ni revocación |41| Dependencias actualizadas y escaneadas | Librerías con CVEs conocidos "porque funciona" |4243---4445## 3. OWASP Top 10 (referencia 2021, vigente)4647El estándar de facto para priorizar riesgos en aplicaciones web. Conócelo de memoria a nivel de qué es y cómo se mitiga.48491. **A01 – Broken Access Control (control de acceso roto):** el usuario accede a datos o acciones que no le corresponden (ver el pedido de otro, escalar a admin). *Mitigar:* denegar por defecto, verificar autorización por objeto en el servidor en CADA request, no exponer IDs adivinables sin check de propiedad. Ver §8.502. **A02 – Cryptographic Failures (fallos criptográficos):** datos sensibles sin cifrar o con cripto débil (contraseñas en SHA plano, TLS opcional, PII en claro). *Mitigar:* TLS obligatorio, cifrado en reposo, algoritmos actuales, hashing lento para contraseñas. Ver §7 y §14.513. **A03 – Injection (inyección):** SQL, NoSQL, comandos de SO, LDAP donde entrada del usuario se interpreta como código. *Mitigar:* consultas parametrizadas, ORM, validación por allowlist, nunca concatenar. Ver §4.524. **A04 – Insecure Design (diseño inseguro):** el fallo está en la arquitectura, no en un bug puntual (flujo de recuperación de cuenta sin verificación, ausencia de límites de negocio). *Mitigar:* threat modeling, patrones seguros desde el diseño, historias de abuso además de historias de usuario.535. **A05 – Security Misconfiguration (configuración insegura):** defaults inseguros, features de debug en producción, permisos abiertos, cabeceras faltantes. *Mitigar:* hardening por defecto, deshabilitar lo no usado, cabeceras de seguridad, revisar config por entorno. Ver §13.546. **A06 – Vulnerable and Outdated Components (componentes vulnerables):** dependencias con CVEs conocidos. *Mitigar:* inventario de dependencias, escaneo continuo, actualizar, lockfiles. Ver §15.557. **A07 – Identification and Authentication Failures (fallos de autenticación):** login débil, sesiones mal gestionadas, credenciales por defecto, sin MFA. *Mitigar:* hashing fuerte, MFA, gestión de sesión robusta, rate limiting. Ver §6 y §9.568. **A08 – Software and Data Integrity Failures (fallos de integridad):** deserialización insegura, actualizaciones o dependencias sin verificar firma, CI/CD comprometido. *Mitigar:* verificar integridad/firmas, no deserializar datos no confiables, proteger el pipeline (supply chain). Ver §15.579. **A09 – Security Logging and Monitoring Failures (fallos de logging y monitoreo):** ataques que pasan inadvertidos por falta de registro o alertas. *Mitigar:* logging de eventos de seguridad, monitoreo y alertas, sin loggear secretos. Ver §16.5810. **A10 – Server-Side Request Forgery (SSRF):** el servidor hace peticiones a URLs controladas por el atacante (acceso a metadata interna, red interna). *Mitigar:* allowlist de destinos, bloquear rangos internos/loopback, no reenviar URLs crudas del usuario.5960---6162## 4. Inyección (SQL / NoSQL / comandos)6364La inyección ocurre cuando datos se interpretan como código. La causa raíz es **mezclar datos y código en la misma cadena**. La solución no es "escapar mejor": es **separar estructuralmente** datos de instrucciones.6566**Regla absoluta: nunca concatenes entrada del usuario en una consulta o comando.**6768```sql69-- ❌ VULNERABLE: la entrada se convierte en código70query = "SELECT * FROM users WHERE email = '" + email + "'"71-- entrada: ' OR '1'='1 → devuelve todos los usuarios7273-- ✅ SEGURO: consulta parametrizada, el driver separa datos de código74query = "SELECT * FROM users WHERE email = ?"75db.execute(query, [email])76```7778- **SQL:** usa consultas parametrizadas / prepared statements SIEMPRE, o un ORM que use bindings por debajo. El placeholder (`?`, `$1`, `:email`) garantiza que el valor jamás se interprete como estructura.79- **NoSQL (p. ej. MongoDB):** también es inyectable. Un `{ "$gt": "" }` inyectado en un campo de contraseña puede saltarse el login. Valida tipos, rechaza operadores en entrada, usa el driver correctamente.80- **Comandos de SO:** evita invocar shell con entrada del usuario. Si es inevitable, usa APIs que reciban argumentos como array (no una cadena de shell) y valida contra allowlist. Nunca `exec("convert " + filename)`.81- **Cuando la parametrización no cubre** (nombres de tabla/columna dinámicos, `ORDER BY`): usa **allowlist** — compara la entrada contra un conjunto fijo de valores válidos, nunca la insertes directa.8283Enlace: al diseñar el acceso a datos, coordina con **database-design** para modelos y permisos de BD con mínimo privilegio.8485---8687## 5. Cross-Site Scripting (XSS)8889XSS ejecuta JavaScript del atacante en el navegador de la víctima. Causa raíz: **datos del usuario tratados como marcado/código en la salida.** La defensa central es **codificar la salida según el contexto**.9091- **Reflejado:** la entrada vuelve inmediatamente en la respuesta (búsqueda que repite el término sin codificar).92- **Almacenado:** la carga se guarda (comentario, perfil) y ataca a todos los que lo ven. El más peligroso.93- **DOM-based:** JS del propio sitio escribe entrada no confiable en el DOM (`innerHTML`, `document.write`).9495Mitigaciones, en capas:9697- **Codificación de salida contextual:** codifica según DÓNDE se inserta el dato — HTML body, atributo, dentro de `<script>`, URL. No es lo mismo. Usa las utilidades del framework (React/Angular/Vue escapan por defecto; respétalas).98- **Nunca uses `innerHTML` / `dangerouslySetInnerHTML` / `v-html`** con datos del usuario. Usa `textContent` o binding seguro. Si DEBES renderizar HTML del usuario, **sanitiza** con una librería robusta (p. ej. DOMPurify) — nunca a mano con regex.99- **Content Security Policy (CSP):** cabecera que restringe de dónde se cargan scripts. Una CSP estricta (sin `unsafe-inline`) convierte muchos XSS en inofensivos aunque la carga llegue. Es tu red de seguridad, no tu primera línea.100- **Cookies con `HttpOnly`:** evita que JS lea la cookie de sesión, limitando el robo de sesión vía XSS.101102```js103// ❌ VULNERABLE104el.innerHTML = "Hola " + userName;105106// ✅ SEGURO107el.textContent = "Hola " + userName;108```109110---111112## 6. CSRF (Cross-Site Request Forgery)113114Un sitio malicioso hace que el navegador de la víctima envíe una petición autenticada a TU sitio (aprovechando su cookie de sesión) sin que ella lo sepa (transferir dinero, cambiar email).115116Mitigaciones:117118- **Tokens anti-CSRF:** token impredecible por sesión/formulario que el servidor emite y verifica en cada petición que cambia estado. El sitio atacante no puede leerlo (same-origin), así que no puede falsificar la petición.119- **Cookies `SameSite`:** `SameSite=Lax` (buen default) o `Strict` impide que la cookie se envíe en peticiones cross-site, cortando el vector de raíz. Combínalo con tokens; no dependas de uno solo.120- **Verifica el método:** las operaciones que cambian estado nunca por `GET`. `GET` es seguro/idempotente por contrato; mutaciones van por `POST/PUT/PATCH/DELETE`.121- Para APIs con tokens en header (no cookies), CSRF clásico no aplica igual, pero valida `Origin`/`Referer` en flujos sensibles.122123---124125## 7. Autenticación (¿quién eres?)126127- **Hashing de contraseñas:** usa un algoritmo **lento y con sal**: **argon2** (preferido), **bcrypt** o **scrypt**. Están diseñados para ser costosos y resistir fuerza bruta con GPU. **NUNCA** MD5, SHA-1, SHA-256/512 planos: son rápidos, y "rápido" es exactamente lo que un atacante quiere para probar millones de hashes.128- **Salting:** cada contraseña con una sal única y aleatoria (bcrypt/argon2 la manejan internamente). La sal impide precomputar (rainbow tables) y hace que dos usuarios con la misma contraseña tengan hashes distintos.129- **Nunca guardes la contraseña en claro ni cifrada de forma reversible.** El hashing es unidireccional a propósito: no necesitas recuperarla, solo verificarla.130- **Políticas sensatas:** longitud mínima razonable (favorece frases largas sobre reglas de complejidad crípticas), compara contra listas de contraseñas filtradas conocidas, no fuerces rotación periódica arbitraria (empeora la higiene).131- **MFA (autenticación multifactor):** ofrécela y exígela para cuentas privilegiadas. Algo que sabes + algo que tienes. Reduce drásticamente el impacto de credenciales robadas.132- **Comparación en tiempo constante** al verificar tokens/OTP para evitar timing attacks.133- **Enumeración de usuarios:** mensajes de login/registro/reset genéricos ("credenciales inválidas"), sin revelar si el email existe. Ver §17.134135---136137## 8. Autorización (¿qué puedes hacer?)138139**Authn ≠ Authz.** Autenticación es *quién eres*; autorización es *qué se te permite*. Estar logueado (authn) no implica poder ver el recurso X (authz). Se verifican por separado, y ambas **en el servidor, siempre**.140141- **Control de acceso a nivel de objeto (IDOR):** el fallo más común. Si `/api/orders/1234` devuelve un pedido, verifica que ese pedido **pertenece al usuario autenticado**, no solo que el usuario esté logueado. Nunca asumas que "como la UI solo le muestra sus IDs, no probará otros". Un atacante cambia el ID a mano en segundos.142143```144❌ getOrder(id) // devuelve cualquier pedido a cualquiera logueado145✅ getOrder(id, currentUser) // verifica ownership: order.userId == currentUser.id146```147148- **RBAC (por roles):** permisos agrupados en roles (`admin`, `editor`, `viewer`). Simple y escalable para la mayoría de casos.149- **ABAC (por atributos):** decisiones según atributos del usuario, recurso y contexto (departamento, hora, ubicación). Más granular, más complejo. Úsalo cuando RBAC se queda corto.150- **Deny by default:** sin regla explícita que permita → denegar.151- **Verifica en cada capa relevante,** no solo en el gateway. Un endpoint interno también autoriza.152153Enlace: al definir endpoints y su modelo de permisos, aplica esto junto con **api-design**.154155---156157## 9. Sesiones y tokens158159**Sesiones (server-side):**160161- ID de sesión aleatorio, largo, impredecible. Cookie con `HttpOnly`, `Secure`, `SameSite`.162- **Regenera el ID de sesión tras el login** (previene session fixation).163- Expiración por inactividad y absoluta. Invalida la sesión en el servidor al cerrar sesión (no basta borrar la cookie).164165**JWT — úsalo entendiendo sus riesgos:**166167- **`alg: none`:** rechaza SIEMPRE tokens sin firma. Fija el algoritmo esperado en el servidor; no dejes que el token dicte su propio algoritmo (ataque clásico de confusión de algoritmo, p. ej. RS256→HS256).168- **No guardes datos sensibles en el payload:** un JWT va firmado pero **no cifrado**; cualquiera lo decodifica en base64 y lee su contenido. Nada de PII, contraseñas ni secretos ahí.169- **Expiración corta (`exp`):** los JWT son difíciles de revocar porque son autocontenidos. Compénsalo con vida corta + **refresh tokens** rotables y revocables.170- **Revocación:** para logout real o cuentas comprometidas necesitas una estrategia (lista de revocación, versión de token en BD, o sesiones server-side). No confíes solo en "el token expira eventualmente".171- **Almacenamiento en el cliente:** preferible cookie `HttpOnly`+`Secure` sobre `localStorage` (este último es legible por cualquier XSS).172173---174175## 10. Gestión de secretos176177Un secreto en el repositorio es un secreto comprometido — asume que ya se filtró.178179- **NUNCA** commitees claves, tokens, contraseñas, cadenas de conexión ni certificados privados. Ni en código, ni en config, ni en tests, ni en el historial.180- Usa **variables de entorno** o, mejor, un **gestor de secretos** (Vault, AWS Secrets Manager, GCP Secret Manager, etc.) con acceso auditado y mínimo privilegio.181- **`.gitignore`** para `.env` y archivos de credenciales; provee un `.env.example` sin valores reales.182- **Rota** los secretos periódicamente y **de inmediato** ante cualquier sospecha de exposición.183- **Si un secreto llegó al repo:** rotarlo es lo primero (invalidar el viejo). Borrarlo del historial es secundario y no sustituye la rotación — el valor ya pudo ser clonado. Coordina esto con **git-workflow** para limpieza de historial y prevención (hooks/escáneres de secretos en pre-commit).184- Escaneo automático de secretos en CI y pre-commit para atraparlos antes del push.185186---187188## 11. Validación de entrada y saneamiento de salida189190Dos operaciones distintas, ambas necesarias:191192- **Validación de entrada (al recibir):** ¿este dato tiene la forma esperada? Tipo, rango, longitud, formato, pertenencia a un conjunto. **Allowlist siempre que puedas:** define lo que ES válido y rechaza el resto. Una denylist ("bloquea `<script>`") siempre olvida un caso; una allowlist ("solo dígitos") no.193- **Saneamiento/codificación de salida (al emitir):** transforma el dato para que sea seguro en su destino (HTML, SQL, shell, log, JSON). El MISMO dato se codifica distinto según a dónde va.194195**Clave: validas al entrar, codificas al salir.** No confundas: validar no hace segura la salida, y codificar no valida la lógica de negocio.196197```198Entrada → validar (¿es un email bien formado? ¿el monto es > 0?)199Proceso → tratar como dato, nunca como código200Salida → codificar según contexto (HTML-encode al render, param al SQL)201```202203- Valida en el servidor aunque el cliente ya valide (el cliente es cosmético).204- Rechaza temprano y explícito; no "arregles" silenciosamente entrada malformada.205206---207208## 12. Transporte y datos209210- **HTTPS/TLS obligatorio** en todo el tráfico, sin excepciones ni "solo en login". El tráfico en claro es interceptable y modificable.211- **HSTS (`Strict-Transport-Security`):** obliga al navegador a usar HTTPS y previene downgrade a HTTP. Actívalo con `max-age` largo.212- **Cifrado en reposo:** datos sensibles y PII cifrados en disco/BD/backups. Gestiona las claves aparte de los datos.213- **PII y minimización de datos:** recolecta solo lo que necesitas, guárdalo el mínimo tiempo, restringe quién accede. El dato que no tienes no se puede filtrar. Considera anonimización/seudonimización cuando el caso de uso lo permita.214- **Datos sensibles fuera de URLs** (quedan en logs, historial, referrers). Van en el cuerpo, no en query strings.215216---217218## 13. Cabeceras de seguridad219220Configúralas por defecto en todas las respuestas:221222- **`Content-Security-Policy`:** controla orígenes de scripts/estilos/recursos. La defensa más potente contra XSS. Empieza restrictiva y afloja lo justo; evita `unsafe-inline`.223- **`Strict-Transport-Security` (HSTS):** fuerza HTTPS (ver §12).224- **`X-Content-Type-Options: nosniff`:** impide que el navegador adivine el MIME type y ejecute algo como script por error.225- **`X-Frame-Options: DENY`** (o CSP `frame-ancestors`): previene clickjacking al no permitir embeber tu sitio en iframes.226- **`Referrer-Policy`** (p. ej. `strict-origin-when-cross-origin`): limita qué URL se filtra en el header `Referer` hacia terceros.227- **`Permissions-Policy`:** restringe APIs del navegador (cámara, geolocalización) que tu app no usa.228229---230231## 14. Criptografía (usar, no inventar)232233- **No implementes cripto propia.** Usa librerías establecidas y revisadas. La cripto casera falla en formas sutiles e invisibles hasta que es tarde.234- Algoritmos actuales y modos correctos (AES-GCM para cifrado autenticado; evita ECB y modos sin autenticación).235- Aleatoriedad **criptográficamente segura** (CSPRNG) para tokens, sales, IDs de sesión — nunca `Math.random()` ni PRNGs de propósito general.236- Gestiona el ciclo de vida de las claves: generación, almacenamiento seguro, rotación, revocación.237- Para contraseñas: hashing lento (§7). Para datos que necesitas recuperar: cifrado simétrico autenticado. Son problemas distintos con herramientas distintas.238239---240241## 15. Dependencias y supply chain242243Tu código es tan seguro como la librería más débil que importas.244245- **Escaneo continuo de vulnerabilidades** (Dependabot, `npm audit`, `pip-audit`, Snyk, etc.) en CI. Trata los CVEs como bugs bloqueantes según severidad.246- **Actualiza** con regularidad; no dejes que las dependencias envejezcan hasta acumular deuda de seguridad.247- **Lockfiles** (`package-lock.json`, `poetry.lock`, `go.sum`) commiteados: builds reproducibles y protección contra sustitución de versiones.248- **Minimiza dependencias:** cada paquete es superficie de ataque y riesgo de código malicioso. ¿Realmente necesitas esa librería para tres líneas?249- **Verifica integridad** (hashes/firmas) de artefactos y del pipeline de build. Protege credenciales de CI/CD: un pipeline comprometido inyecta en todo lo que despliega.250251---252253## 16. Logging seguro254255El logging es doble filo: esencial para auditoría, peligroso si registra lo que no debe.256257- **NUNCA loggees:** contraseñas, tokens, claves de API, cookies de sesión, PII sensible, números completos de tarjeta, contenido de secretos. Ni siquiera "temporalmente para debug" — esos logs persisten y se filtran.258- **SÍ registra para auditoría:** intentos de login (éxito y fallo), cambios de permisos, accesos a datos sensibles, operaciones administrativas, errores de seguridad. Con quién, qué, cuándo y desde dónde — sin el contenido secreto.259- **Enmascara/redacta** datos sensibles antes de escribir (p. ej. `****1234`).260- Protege los logs mismos: acceso restringido, retención definida, sin exponerlos públicamente.261262Enlace: para el diseño de logging estructurado, correlación, niveles y qué es auditable, apóyate en **error-handling-observability**.263264---265266## 17. Manejo de errores y menor exposición267268- **No filtres internals al cliente:** stack traces, mensajes de la BD, rutas de archivos, nombres de frameworks o versiones. Ayudan al atacante a mapear el sistema. Al cliente: mensaje genérico + un ID de correlación. El detalle va al log interno.269- **Mensajes uniformes** en flujos sensibles (login, reset, registro): no reveles si el email existe, si la contraseña era casi correcta, etc. Evita la enumeración.270- **Menor exposición en respuestas de API:** devuelve solo los campos necesarios. Nada de `SELECT *` serializado crudo que arrastre `password_hash`, flags internos o campos de otros usuarios. Define DTOs de salida explícitos (allowlist de campos), no listas de exclusión.271- **Fail securely (§1):** un error en la verificación de permisos deniega, no permite.272273---274275## 18. Rate limiting y anti-abuso276277- **Rate limiting** en autenticación, reset de contraseña, verificación de OTP y endpoints costosos. Frena fuerza bruta y credential stuffing.278- **Backoff / bloqueo temporal** tras varios intentos fallidos, con cuidado de no habilitar un DoS por bloqueo (prefiere throttling progresivo + CAPTCHA sobre lockout permanente).279- **Anti-enumeración:** respuestas y tiempos uniformes para no revelar existencia de recursos/usuarios (§17).280- **Límites de negocio:** además de límites técnicos, pon topes lógicos (máximo de transferencias, de creación de recursos) para contener abuso automatizado.281282---283284## Anti-patrones comunes285286- "Lo valido en el frontend, con eso basta." — El cliente es inspeccionable y modificable. Toda validación de seguridad es del lado servidor.287- Concatenar entrada en SQL/comandos "porque el ORM es lento aquí".288- `md5(password)` o `sha256(password)` para guardar contraseñas.289- Comprobar `if (user.isLoggedIn)` y asumir que eso autoriza el acceso al objeto (falta el check de ownership → IDOR).290- Guardar el JWT en `localStorage` y meter datos sensibles en su payload.291- Secretos hardcodeados "temporalmente" que terminan en el historial de git.292- Denylist de caracteres "peligrosos" en lugar de allowlist de lo válido.293- Devolver el stack trace al cliente en producción para "facilitar el debug".294- Desactivar la verificación de certificados TLS (`verify=False`) para que "funcione ya".295- `Math.random()` para generar tokens o IDs de sesión.296- Loggear el request completo (con Authorization header y body) "para debug".297- Confiar en `Referer`/`Origin` como ÚNICA defensa CSRF sin tokens ni `SameSite`.298- Endpoint nuevo abierto por defecto "porque todavía no configuré permisos".299300---301302## Checklist de seguridad antes de exponer303304- [ ] Toda entrada del usuario se valida en el servidor (allowlist)305- [ ] Consultas parametrizadas / ORM; cero concatenación en SQL/NoSQL/shell306- [ ] Salida codificada según contexto; sin `innerHTML` con datos de usuario307- [ ] Autenticación con hashing fuerte (argon2/bcrypt/scrypt) + sal308- [ ] Autorización verificada en el servidor y por objeto (sin IDOR)309- [ ] Sesiones/tokens: expiración, revocación, cookies `HttpOnly`+`Secure`+`SameSite`310- [ ] JWT: algoritmo fijado, `alg:none` rechazado, sin datos sensibles en el payload311- [ ] Sin secretos en el repo; en gestor de secretos o variables de entorno312- [ ] HTTPS/TLS obligatorio y HSTS activo313- [ ] Cabeceras de seguridad configuradas (CSP, nosniff, X-Frame-Options, Referrer-Policy)314- [ ] CSRF cubierto (tokens + `SameSite`) en operaciones que cambian estado315- [ ] Rate limiting en login, reset y endpoints costosos316- [ ] Dependencias escaneadas, actualizadas y con lockfile commiteado317- [ ] Logs sin secretos/PII; eventos de seguridad auditados318- [ ] Errores genéricos al cliente; sin stack traces ni versiones expuestas319- [ ] Respuestas de API con solo los campos necesarios (DTO de salida)320- [ ] Cifrado en reposo para datos sensibles; PII minimizada321- [ ] Fail securely verificado: los errores deniegan, no permiten322323---324325## Skills relacionados326327- **api-design** — modelado de endpoints, contratos y permisos por recurso.328- **error-handling-observability** — logging estructurado, correlación y manejo de errores sin fuga de internals.329- **database-design** — modelo de datos, permisos de BD con mínimo privilegio, cifrado en reposo.330- **git-workflow** — prevención y limpieza de secretos en el historial, hooks y escáneres en pre-commit.331332---333334## Referencias335336- **OWASP Top 10** — https://owasp.org/www-project-top-ten/337- **OWASP Cheat Sheet Series** — https://cheatsheetseries.owasp.org/ (guías concretas por tema: Authentication, Authorization, SQL Injection Prevention, XSS Prevention, CSRF, Password Storage, JWT, Secrets Management, Logging)338- **OWASP ASVS** (Application Security Verification Standard) — requisitos verificables por nivel.339- **OWASP API Security Top 10** — riesgos específicos de APIs.340- **CWE Top 25** — debilidades de software más peligrosas.341- **NIST SP 800-63B** — guía moderna de contraseñas y autenticación.
Run npx skillmds@latest add julianramirezreyes/security in your terminal (requires Node.js), paste this page's agent-chat prompt into Claude, Cursor, or any MCP-connected agent, or download the SKILL.md file and copy it into your agent's skills directory.
Seguridad aplicada: OWASP, autenticación/autorización, secretos, validación, defensa en profundidad. It is listed under Security on SkillMD.
This skill has not completed SkillMD's automated safety review yet. Capability flags: makes network calls, reads secrets. SkillMD never runs a skill's scripts for you; review the SKILL.md before installing.
This skill is tagged as working with Claude Code, Claude.ai, OpenAI Codex. SKILL.md is an open format, so most agents that read a skills directory can load it too.
Yes. Installing skills from SkillMD is free, and the skill stays under its author's original license.
julianramirezreyes (@julianramirezreyes) published this skill. Their other Agent Skills are listed on their SkillMD profile.