Seguridad de aplicaciones JavaScript: top 10 vulnerabilidades en la práctica

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: por qué la seguridad de las aplicaciones JavaScript no es una opción, sino una necesidad

JavaScript (especialmente en la plataforma Node.js) se ha convertido en el lenguaje dominante para crear aplicaciones tanto del lado del cliente como del servidor. Sin embargo, con el aumento de la popularidad también crece el número de ataques. Según OWASP, la mayoría de las intrusiones ocurren debido a errores típicos que se pueden prevenir. En este artículo analizaremos el top 10 de vulnerabilidades de JavaScript (Node.js) con ejemplos de código reales y métodos de protección. El material será útil tanto para desarrolladores principiantes como experimentados que deseen fortalecer la seguridad de sus proyectos.



1. Inyecciones (SQL, NoSQL, Command Injection)

Las inyecciones siguen siendo la categoría de vulnerabilidades más peligrosa. En Node.js, MongoDB y PostgreSQL suelen verse afectados.



Ejemplo de código vulnerable (inyección NoSQL):

// Código vulnerableapp.post('/login', async (req, res) => {  const { username, password } = req.body;  const user = await db.collection('users').findOne({    username: username,    password: password  });  // Si se pasa { "username": { "$ne": null }, "password": { "$ne": null } }, se devolverá el primer usuario});


Cómo corregirlo:

  • Utilice ORM/ODM con parametrización (Mongoose, Sequelize).
  • Valide y sanitice los datos de entrada (biblioteca validator o joi).
  • Para comandos, use execFile en lugar de exec.


2. Cross-Site Scripting (XSS)

XSS permite a un atacante inyectar un script malicioso en una página que otros usuarios están viendo.



Ejemplo de código vulnerable (XSS Reflejado):

// Ruta Express vulnerableapp.get('/search', (req, res) => {  const query = req.query.q;  res.send(`<h1>Resultados de búsqueda para: ${query}</h1>`);  // Si se pasa ?q=<script>alert('XSS')</script>, el script se ejecutará});


Protección:

  • Escape la salida: use res.render con motores de plantillas (EJS, Pug) o encodeURIComponent.
  • Establezca el encabezado HTTP Content-Security-Policy.
  • No use innerHTML en el cliente — aplique textContent.


3. Autenticación insegura y gestión de sesiones

La autenticación débil es una de las principales causas de filtraciones de datos. A menudo, los desarrolladores hardcodean claves o usan contraseñas débiles.



Errores típicos:

  • Almacenar contraseñas en texto plano (en lugar de bcrypt/argon2).
  • Usar secretos JWT predecibles (secret123).
  • Falta de limitación en el número de intentos de inicio de sesión.


Ejemplo de implementación correcta:

const bcrypt = require('bcrypt');const saltRounds = 12;

app.post('/register', async (req, res) => { const hash = await bcrypt.hash(req.body.password, saltRounds); // Guardamos el hash en la BD});

app.post('/login', async (req, res) => { const user = await db.getUser(req.body.username); const match = await bcrypt.compare(req.body.password, user.passwordHash); if (match) { // Creamos un JWT con corta duración const token = jwt.sign({ id: user.id }, process.env.JWT_SECRET, { expiresIn: '15m' }); res.json({ token }); }});


4. SSRF (Server-Side Request Forgery)

La vulnerabilidad SSRF permite a un atacante hacer que el servidor realice solicitudes a recursos internos (por ejemplo, a los metadatos del proveedor de la nube).



Ejemplo:

// Código vulnerable: carga de avatar por URLapp.post('/avatar', async (req, res) => {  const { url } = req.body;  const response = await fetch(url); // Se puede pasar http://169.254.169.254/latest/meta-data/  // Procesamiento de la respuesta});


Protección:

  • Cree una lista blanca de dominios permitidos.
  • Blo

Blogs

Book Recommendations