Skip to content
This page has been auto-translated and may contain errors.View in English

Introducción a la ciberseguridad

La mayoría de los fallos de seguridad en aplicaciones web son errores de programación comunes con una consecuencia poco común.

Una consulta se arma pegando strings entre sí. Una plantilla escribe el nombre de un visitante directo en la página. Una ruta lee un id de la URL y devuelve el registro sin verificar quién lo pidió.

Cada uno de estos casos parece razonable en una revisión, hasta el momento en que ves la petición que se aprovecha de él.

El trabajo de seguridad consiste sobre todo en tener el hábito de preguntarte qué haría una versión hostil de este input.

Cada uno de esos fallos se ubica en un límite de confianza, que es la idea más útil de todo este manual.

¿Qué es un límite de confianza?

Un límite de confianza es la línea entre una parte de tu sistema que controlas y una que no: el navegador, una API de terceros, un archivo subido por el usuario. Todo lo que cruce esa línea tiene que verificarse del otro lado.

Cómo pensar la seguridad explica dónde trazar esas líneas en una aplicación web típica.

Qué cubre este manual

Esto es seguridad de aplicaciones para desarrolladores: la seguridad del código que tú escribes, revisas y publicas.

No cubre seguridad de redes, análisis de malware, monitoreo de blue team, operaciones de red team ni marcos de cumplimiento normativo. Son campos amplios con su propia literatura, y a quien busque eso le conviene más ir directo a esas fuentes.

Todos los ejemplos de código usan Node y Express, con Zod para describir la forma de los datos que se esperan, así que los ejemplos se parecen a un servicio que tú mismo podrías estar manteniendo.

Los capítulos se organizan en cuatro partes, pensadas para leerse en orden la primera vez, porque las últimas se apoyan en el vocabulario que la primera define.

ParteQué cubreEmpieza en
1 · Pensar como un atacanteIdentificar por dónde entran los datos externos, STRIDE para anticipar amenazas, OWASP para nombrar las que ya se conocen, y cómo redactar un reporte de bugCómo pensar la seguridad
2 · Seguridad de datos e inputsLos ataques famosos, que resultan ser el mismo error disfrazado de distintas formas, y luego la validación que los cierra todos a la vezNunca confíes en el input del usuario
3 · Autenticación e identidadHTTP te olvida entre peticiones, así que cada aplicación elige una forma de recordarte. Tres formas, comparadasAutenticación vs. autorización
4 · Rate limiting y throttlingMantener el servicio respondiendo cuando el tráfico es hostil. Cinco algoritmos y dos respuestasFundamentos de rate limiting
JunoQué cubre este manual Nos quedamos en un solo rincón de la seguridad: el código que tú escribes y revisas, con Node y Express, y Zod verificando todo lo que llega.

Cuatro partes, que empiezan con cómo pensar y terminan con cómo mantener un servicio en pie. A mí todavía se me da por volver a la primera parte más que a cualquiera de las otras.

JunoQué cubre este manual El alcance es la seguridad de aplicaciones en Node, Express y Zod. Redes, malware, blue team y cumplimiento normativo quedan fuera.

Lee las partes en orden la primera vez. La parte 3 asume el vocabulario de inputs de la parte 2, y la parte 4 asume que ya puedes identificar un cliente, algo que la parte 3 establece.

JunoQué cubre este manual El alcance es acotado a propósito: el código del que eres responsable, y ninguno de los otros campos que se agrupan bajo la misma palabra.

Vale la pena saber qué cuesta esa acotación. El almacenamiento de contraseñas, los patrones de control de acceso, CSRF, los encabezados de respuesta y los riesgos de la cadena de suministro se mencionan cuando algún capítulo los necesita, pero ninguno tiene su propio capítulo.

Cuando te topes con uno de verdad, ve al cheat sheet de OWASP correspondiente. Este manual ya te habrá dado el vocabulario para entenderlo.

Qué necesitas saber antes

Vas a sacarle más provecho a esto si puedes escribir un poco de JavaScript y ya has visto un servidor pequeño de Node y Express. Suficiente para reconocer una ruta y una función de middleware cuando las veas.

Una idea hace más trabajo aquí que cualquier otra. Cuando alguien visita tu sitio, su navegador envía una petición: la dirección que pidió, algunos encabezados y, a menudo, un body que lleva lo que sea que haya escrito.

Cada una de esas piezas fue escrita por esa persona, incluyendo las que tu propia página completó de antemano.

Nada le impide a alguien saltarse tu página y enviar lo que se le antoje.

Un detalle de Express hay que tenerlo presente desde el inicio, porque la mayoría de las soluciones dependen de él. El middleware se ejecuta en el orden en que lo registras, así que una validación tiene que ir antes de la ruta que confía en su resultado. Una registrada después no protege nada.

El manual de JavaScript cubre el lado del lenguaje, y su capítulo sobre el DOM prepara el terreno para los capítulos de aquí sobre cómo escapar lo que escribes en una página.

JunoQué necesitas saber antes Con JavaScript y un poco de Node alcanza para empezar. La idea que debes llevarte es que cada parte de una petición fue escrita a mano por quien la envió, incluyendo los campos que tu propia página completó.

A mí me tomó un tiempo dejar de tratar mi propio front end como una fuente confiable, y casi todo lo demás se vuelve más fácil una vez que lo haces. Tampoco se asume ningún conocimiento previo de seguridad.

JunoQué necesitas saber antes Trata cada campo de req como controlado por el atacante. La petición llega a través de varias propiedades, y una validación en una no dice nada sobre las demás: req.params guarda los segmentos de la ruta, req.query el query string, req.body el body ya parseado, req.headers el resto.

Así que un schema sobre req.body deja sin ninguna validación a un handler que más adelante lee req.query.sort.

JunoQué necesitas saber antes El modelo de amenazas es la petición completa: encabezados, cookies, body, ruta, cada campo que tu propio cliente completa.

Ten en cuenta también el runtime. El razonamiento se traslada entre stacks; los valores por defecto y el modelo de concurrencia casi nunca lo hacen. El event loop único de Node es el caso más extremo, ya que una expresión regular construida de forma que haga backtracking, o una llamada de hash síncrona en un handler, bloquea todas las demás peticiones en curso.

Un bug de tamaño de input que un servidor con un hilo por petición absorbe como latencia, aquí se convierte en un fallo de disponibilidad.

Cómo enseñamos las vulnerabilidades

Cada capítulo que cubre una debilidad real sigue los mismos cuatro pasos, así que una vez que leas uno ya conoces el recorrido de todos los demás.

  1. El código con el fallo, lo bastante corto para leerlo de una sola vez y parecido a algo que encontrarías en un proyecto real.
  2. El payload, el input o la petición concreta que lo rompe.
  3. Por qué funciona, rastreado a través del código, porque una corrección que no puedes explicar es una corrección que vas a deshacer más adelante.
  4. La corrección, con una nota sobre qué variantes cubre y cuáles no.

Al tamaño que un capítulo introductorio puede manejar, los cuatro pasos se ven así:

js
// Vulnerable: el nombre se pega directo en el texto de la consulta
app.get('/users', (req, res) => {
  const rows = db.query(`SELECT * FROM users WHERE name = '${req.query.name}'`)
  res.json(rows)
})

// Payload: /users?name=' OR 1=1 --
// La comilla cierra el string antes de tiempo, así que OR 1=1 termina en la
// consulta como una condición propia y coincide con todas las filas de la tabla.

// Corregido: el valor viaja junto a la consulta y nunca se interpreta como SQL
const rows = db.query('SELECT * FROM users WHERE name = ?', [req.query.name])

Mostrar el payload es deliberado. Una inyección descrita en abstracto pasa desapercibida, y ese mismo fallo es difícil de detectar a las tres de la tarde en el pull request de otra persona.

Un límite se aplica en todo momento

Estos payloads están aquí para que puedas encontrar este tipo de fallo en código del que seas responsable. Úsalos solo contra sistemas propios o con permiso explícito para hacer pruebas, y en ningún otro lugar.

Este manual también se mantiene dentro de ese límite: sin herramientas de escaneo, sin objetivos de terceros, sin evasión de detección y sin guías para encadenar una debilidad con otra.

JunoCómo enseñamos las vulnerabilidades Ver un payload funcional puede sentirse raro al principio, como si te entregaran algo prohibido. Es la misma razón por la que una clase de seguridad alimentaria te muestra cómo se ve la comida en mal estado: reconocerla es justamente el objetivo.

La regla que debes recordar es usar esto únicamente contra tus propios proyectos.

JunoCómo enseñamos las vulnerabilidades Los mismos cuatro pasos cada vez: código vulnerable, payload, por qué funciona, la corrección. Lee el payload con atención cada vez, porque eso es justo lo que vas a estar reconociendo por patrones más adelante en una revisión.

El paso que la gente se salta es el tercero. Una corrección que adoptaste sin entenderla termina siendo eliminada por la siguiente persona que la encuentre inconveniente.

JunoCómo enseñamos las vulnerabilidades La explotabilidad es lo que separa un hallazgo que vale la pena corregir esta semana de una simple nota en el backlog, y solo puedes evaluarla frente a un payload concreto. Por eso cada capítulo incluye uno.

El paso cuatro importa igual de mucho. Una corrección sin un alcance definido se convierte en leyenda: alguien la aplica a un caso que nunca cubría, y el hueco sobrevive a una revisión que parecía exhaustiva. Cada corrección aquí indica qué cierra y qué no.

Conoce a tus guías

Tres guías acompañan este manual, y tú eliges cuál te lleva de la mano.

Todos leen la misma base, escrita en un lenguaje sencillo para alguien que se encuentra con la seguridad por primera vez. Elegir una guía más profunda añade material extra: el patrón más amplio, los casos que la primera corrección no cubre, las decisiones de compromiso detrás de ella. Tu guía también define el tono.

Cambia de guía cuando quieras desde el selector en la parte superior de cualquier página, o abre Preferencias abajo a la derecha para cambiar de guía o de tamaño de letra.

El nivel es la profundidad que quieres ese día, así que cámbialo cuando un capítulo te resulte demasiado superficial o demasiado denso. Subir de nivel a mitad de un capítulo agrega el material extra en su lugar, sin mover lo que ya leíste.

JunoConoce a tus guías Hola de nuevo, soy yo. Beginner aquí no significa principiante en programación, significa nuevo en seguridad, y así está la mayoría de la gente.

Si un capítulo se siente pesado, prueba bajar de nivel en esa página. No se pierde nada, y la base es la misma por debajo.

JunoConoce a tus guías La página base es la misma sin importar qué guía elijas. Lo que cambia es quién está a tu lado y qué tan a fondo va.

Vale la pena cambiar de guía en un tema que ya conoces bien: es la forma más rápida de descubrir qué nivel te conviene para el resto del recorrido.

JunoConoce a tus guías La profundidad aquí es criterio de producción más que detalles internos por sí mismos: qué cuesta una corrección, dónde deja de funcionar y qué compromiso estás aceptando.

Elige este nivel porque es la profundidad que quieres hoy, no por cuánto tiempo llevas haciendo esto. Muchos desarrolladores con experiencia leen la ruta base cuando el tema les es poco familiar, y después vuelven a subir.

Hacia dónde va esto

Cuatro partes, treinta y dos capítulos, un ejemplo de trabajo que se rompe y se repara una y otra vez a lo largo del recorrido.

¿Qué es la ciberseguridad? acota la palabra antes de que llegue cualquier vocabulario, y luego cómo pensar la seguridad empieza el hábito sobre el que corre el resto del manual.

¿Prefieres aprender construyendo?El curso de Ciberseguridad de Scrimba cubre lo mismo a través de desafíos interactivos que resuelves en el navegador.