← Blog
·9 min read

Ciberseguridad para Programadores Principiantes: La Guía desde Cero

Si nunca has pensado en seguridad, este post es para ti. Ciberseguridad para programadores principiantes — conceptos básicos, sin jerga, con ejemplos reales.

Rod

Founder & Developer

Si nunca has pensado en ciberseguridad para programadores principiantes, este post es para ti. No en plan condescendiente — sino porque la realidad es que la mayoría de los cursos de programación no enseñan seguridad. Aprendes a construir cosas que funcionan. Nadie te dice cómo construir cosas que no se rompan cuando alguien intenta atacarlas.

La buena noticia: los errores más comunes son predecibles. Y evitarlos no requiere un título en seguridad informática.


Qué es realmente la seguridad en el código

La seguridad informática básica para devs se resume en una idea: asegurarte de que solo las personas correctas puedan hacer las cosas correctas con tus datos.

Eso suena simple. El problema es que cuando estás construyendo una feature, tu cabeza está en que funcione. No en quién podría abusar de ella.

Un atacante piensa diferente. Busca inputs que no validaste. Busca endpoints que olvidaste proteger. Busca datos que quedaron expuestos por error. No es que sean genios — es que tienen tiempo y motivación para intentar cosas que a ti no se te ocurrirían.

El OWASP Top 10 es la lista de los diez tipos de vulnerabilidad más frecuentes. En 2025, sigue cubriendo el 80% de los ataques reales. Si entiendes esa lista, entiendes el mapa del campo.


Los 5 errores de seguridad más comunes (con ejemplos reales)

1. Secretos hardcodeados en el código

Este es el error numero uno en repos de principiantes — y de equipos con experiencia. Pones tu API key directo en el código porque "es más fácil" o porque la IA te la generó así.

// MAL: tu API key de OpenAI visible en el código fuente
const openai = new OpenAI({ apiKey: "sk-proj-xxxxxxxxxxxx" });
 
// BIEN: leerla desde variables de entorno
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

El problema con el primer ejemplo: si subes ese código a GitHub — incluso en un repo privado — esa key está comprometida. Hay bots que escanean commits en tiempo real buscando exactamente ese patrón. GitHub Copilot, Cursor, y la mayoría de herramientas de IA guardan contexto de lo que escribiste.

Las variables de entorno van en un archivo .env que agregas a .gitignore. Nunca subes ese archivo. Nunca.

Si ya hiciste commit de un secreto: rótalo inmediatamente. Cambiar el .env no borra el historial de Git. Tienes que ir al proveedor (OpenAI, Stripe, lo que sea) y generar una nueva key.

2. Inputs sin validar

Tu app recibe datos del usuario. ¿Qué pasa si alguien mete algo que no esperabas?

El ataque más clásico se llama SQL injection. Ocurre cuando construyes una query de base de datos concatenando strings con input del usuario.

// MAL: concatenar input del usuario en una query SQL
const query = `SELECT * FROM users WHERE email = '${email}'`;
 
// BIEN: usar una query parametrizada (el driver maneja el escaping)
const { data } = await supabase
  .from("users")
  .select("*")
  .eq("email", email); // Supabase maneja el escaping automáticamente

Si alguien mete ' OR '1'='1 como email en el primer caso, la query devuelve todos los usuarios de la base de datos. Eso es un problema.

La solución no es complicada: usa un ORM o queries parametrizadas. Casi nunca deberías construir una query SQL con strings concatenados.

3. Rutas de API sin verificar quién pregunta

Construiste un endpoint /api/users/[id] que devuelve los datos de un usuario. ¿Verificas que el usuario autenticado tiene permiso para ver ese ID?

Si no, cualquiera que sepa la URL puede ver los datos de cualquier usuario. Esto se llama Broken Access Control y es el #1 del OWASP Top 10.

// MAL: no verificar que el usuario tiene permiso
export async function GET(req: Request, { params }: { params: { id: string } }) {
  const user = await getUserById(params.id); // cualquiera puede hacer esto
  return Response.json(user);
}
 
// BIEN: verificar sesión y que el ID corresponde al usuario autenticado
export async function GET(req: Request, { params }: { params: { id: string } }) {
  const session = await getSession();
  if (!session) return Response.json({ error: "No autorizado" }, { status: 401 });
  if (session.user.id !== params.id) return Response.json({ error: "Prohibido" }, { status: 403 });
 
  const user = await getUserById(params.id);
  return Response.json(user);
}

La regla: cada endpoint que devuelve o modifica datos debe verificar quién está haciendo la petición y si tiene permiso de hacerlo.

4. Dependencias desactualizadas con vulnerabilidades conocidas

Tu package.json tiene 40 dependencias. Cada una tiene sus propias dependencias. Algunas de esas tienen vulnerabilidades conocidas — publicadas en bases de datos públicas con instrucciones de cómo explotarlas.

No necesitas entender cada CVE. Necesitas saber cuándo tienes alguno.

# Revisar vulnerabilidades en tus dependencias de Node.js
npm audit
 
# Ver solo las críticas y altas
npm audit --audit-level=high

npm audit es gratis, está incluido en Node.js, y tarda 10 segundos. Córrelo antes de cada deploy. Si hay vulnerabilidades críticas, actualiza el paquete antes de subir a producción.

5. XSS — meter código de terceros en tu página

Cross-Site Scripting (XSS) ocurre cuando muestras en tu página HTML que viene de un usuario sin escaparlo. Si alguien mete <script>alert('hackeado')</script> en un comentario y tú lo renderizas directo, ese script corre en el browser de todos los que visiten la página.

// MAL: renderizar HTML de usuario directamente (dangerouslySetInnerHTML sin sanitizar)
<div dangerouslySetInnerHTML={{ __html: userComment }} />
 
// BIEN: renderizar como texto o usar una librería de sanitización
<p>{userComment}</p>
// O si necesitas HTML del usuario:
import DOMPurify from "dompurify";
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(userComment) }} />

React por default escapa el contenido. El peligro llega cuando usas dangerouslySetInnerHTML sin pensar, o cuando construyes HTML con concatenación de strings en el servidor.


La mentalidad de seguridad: pensar como atacante

Cuando termines de construir una feature, hazte estas preguntas:

  • ¿Qué pasa si alguien manda inputs raros? Strings muy largos, caracteres especiales, números negativos, objetos JSON anidados.
  • ¿Qué pasa si alguien llama este endpoint sin estar autenticado?
  • ¿Qué pasa si un usuario autenticado intenta acceder a datos de otro usuario?
  • ¿Hay datos sensibles en los logs? Contraseñas, tokens, datos de tarjetas.
  • ¿Este error expone información interna? Stack traces con rutas de archivo, nombres de tablas de base de datos.

No tienes que anticipar todos los ataques posibles. Tienes que hacer las preguntas obvias.

Una vulnerabilidad no requiere un atacante sofisticado. La mayoría de los ataques reales son simples: alguien probó una URL diferente y funcionó.


Cómo revisar tu código actual sin ser experto en seguridad

Si ya tienes código en producción y quieres saber si tiene problemas, hay formas de revisarlo sin saber de seguridad de antemano.

Data Hogo escanea tu repo de GitHub y te dice exactamente qué encontró: secretos expuestos, dependencias con vulnerabilidades, endpoints sin protección, configuraciones inseguras. Cada hallazgo viene con una explicación en español de qué es, por qué importa, y cómo arreglarlo.

Escaneamos cientos de repos y los patrones son consistentes. El 70% de los proyectos tienen al menos una API key expuesta o una dependencia con CVE activo. No porque los devs sean descuidados — sino porque nadie los revisó.

Escanea tu repo gratis — sin tarjeta de crédito →

El plan gratis incluye 3 escaneos al mes. Tarda menos de 5 minutos.


Por dónde seguir aprendiendo

Dominar los cinco errores de arriba te pone por delante del 80% de los proyectos que vemos. Cuando quieras ir más profundo:

La ciberseguridad para programadores principiantes no requiere memorizar CVEs ni convertirte en pentester. Requiere hábitos: validar inputs, no hardcodear secretos, verificar permisos. Con esos tres hábitos evitas la mayoría de los ataques reales.


Preguntas frecuentes

¿Por dónde empiezo a aprender ciberseguridad como programador?

Empieza por los errores más comunes en tu propio código: secretos hardcodeados, inputs sin validar, y dependencias desactualizadas. El OWASP Top 10 es la lista de referencia — cubre el 80% de los ataques reales que ocurren hoy. No necesitas ser experto en seguridad para entender y corregir estos patrones.

¿Qué es una vulnerabilidad de seguridad?

Es un error en tu código o configuración que permite a alguien hacer algo que no debería poder hacer — leer datos que no son suyos, modificar información, o tomar control de tu servidor. La mayoría no son bugs complejos: son errores comunes de programación como no validar un input o dejar una API key en el código.

¿Qué es SQL injection y cómo se previene?

SQL injection ocurre cuando alguien mete código SQL en un campo de tu app y tu servidor lo ejecuta directamente. Se previene con queries parametrizadas o un ORM que maneje el escaping automáticamente — nunca construyas queries SQL concatenando strings con input del usuario.

¿Cómo sé si mi app tiene vulnerabilidades de seguridad?

La forma más rápida es conectar tu repo de GitHub a un scanner automático. Data Hogo escanea tu código en menos de 5 minutos y te dice exactamente qué encontró, dónde está, y cómo arreglarlo — en español. El plan gratis incluye 3 escaneos al mes sin tarjeta de crédito.

¿Tengo que saber de seguridad para hacer apps seguras?

No necesitas ser experto. Con dominar cuatro o cinco patrones básicos — no hardcodear secretos, validar inputs, mantener dependencias actualizadas, verificar autenticación en cada endpoint — evitas la gran mayoría de ataques reales. La seguridad perfecta no existe, pero la seguridad básica es más accesible de lo que parece.

ciberseguridadprincipiantesseguridad básicavulnerabilidadesdevs