Seguridad Web: OWASP Top 10 y Cómo Protegerte

24 de diciembre de 2025
Osman Jimenez
Seguridad OWASP Desarrollo Web

Protegiendo Aplicaciones Web

La seguridad es crítica. Aprende las vulnerabilidades más comunes según OWASP y cómo proteger tus aplicaciones.

1. Broken Access Control

// ❌ Vulnerable
app.get('/api/users/:id', (req, res) => {
  const user = await User.findById(req.params.id);
  res.json(user);
});

// ✅ Seguro
app.get('/api/users/:id', authenticate, (req, res) => {
  if (req.user.id !== req.params.id && !req.user.isAdmin) {
    return res.status(403).json({ error: 'Forbidden' });
  }
  const user = await User.findById(req.params.id);
  res.json(user);
});

2. Cryptographic Failures

// ❌ Nunca guardes passwords en texto plano
const user = { password: 'password123' };

// ✅ Usa bcrypt
import bcrypt from 'bcrypt';

const hashedPassword = await bcrypt.hash(password, 10);
const isValid = await bcrypt.compare(password, hashedPassword);

// ✅ Usa HTTPS siempre
// ✅ Encripta datos sensibles en BD

3. Injection (SQL, NoSQL, Command)

// ❌ SQL Injection vulnerable
const query = `SELECT * FROM users WHERE email = '${email}'`;

// ✅ Usa prepared statements
const query = 'SELECT * FROM users WHERE email = ?';
const users = await db.query(query, [email]);

// ❌ NoSQL Injection
User.find({ email: req.body.email });

// ✅ Valida y sanitiza
const email = validator.isEmail(req.body.email) ? req.body.email : null;
if (!email) return res.status(400).json({ error: 'Invalid email' });

4. Insecure Design

// Implementa rate limiting
import rateLimit from 'express-rate-limit';

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 100
});

app.use('/api/', limiter);

// Implementa CAPTCHA para acciones sensibles
// Usa 2FA para autenticación

5. Security Misconfiguration

// ❌ Exponer información sensible
app.use((err, req, res, next) => {
  res.status(500).json({ error: err.stack });
});

// ✅ Ocultar detalles en producción
app.use((err, req, res, next) => {
  console.error(err);
  res.status(500).json({ 
    error: process.env.NODE_ENV === 'production' 
      ? 'Internal Server Error' 
      : err.message 
  });
});

// Configurar headers de seguridad
import helmet from 'helmet';
app.use(helmet());

6. Vulnerable Components

# Auditar dependencias
npm audit
npm audit fix

# Usar Snyk o Dependabot
# Mantener dependencias actualizadas
npm outdated
npm update

7. Authentication Failures

// Implementar JWT correctamente
import jwt from 'jsonwebtoken';

const token = jwt.sign(
  { userId: user.id },
  process.env.JWT_SECRET,
  { expiresIn: '1h' }
);

// Validar tokens
const authenticate = (req, res, next) => {
  const token = req.headers.authorization?.split(' ')[1];
  
  if (!token) {
    return res.status(401).json({ error: 'No token' });
  }
  
  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    req.user = decoded;
    next();
  } catch (error) {
    res.status(401).json({ error: 'Invalid token' });
  }
};

8. Software and Data Integrity Failures

// Verificar integridad de archivos subidos
import crypto from 'crypto';

function verifyChecksum(file, expectedHash) {
  const hash = crypto.createHash('sha256');
  hash.update(file);
  return hash.digest('hex') === expectedHash;
}

// Usar Subresource Integrity (SRI)

9. Logging and Monitoring Failures

// Implementar logging adecuado
import winston from 'winston';

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.json(),
  transports: [
    new winston.transports.File({ filename: 'error.log', level: 'error' }),
    new winston.transports.File({ filename: 'combined.log' })
  ]
});

// Log eventos de seguridad
logger.warn('Failed login attempt', { 
  email, 
  ip: req.ip,
  timestamp: new Date()
});

10. Server-Side Request Forgery (SSRF)

// ❌ Vulnerable
app.get('/fetch', async (req, res) => {
  const url = req.query.url;
  const response = await fetch(url);
  res.send(await response.text());
});

// ✅ Validar URLs
const allowedDomains = ['api.example.com'];

app.get('/fetch', async (req, res) => {
  const url = new URL(req.query.url);
  
  if (!allowedDomains.includes(url.hostname)) {
    return res.status(400).json({ error: 'Invalid domain' });
  }
  
  const response = await fetch(url.toString());
  res.send(await response.text());
});

XSS Prevention

// Sanitizar input
import DOMPurify from 'isomorphic-dompurify';

const clean = DOMPurify.sanitize(dirtyHTML);

// Content Security Policy
app.use(helmet.contentSecurityPolicy({
  directives: {
    defaultSrc: ["'self'"],
    scriptSrc: ["'self'", "'unsafe-inline'"],
    styleSrc: ["'self'", "'unsafe-inline'"]
  }
}));

CSRF Protection

import csrf from 'csurf';

const csrfProtection = csrf({ cookie: true });

app.get('/form', csrfProtection, (req, res) => {
  res.render('form', { csrfToken: req.csrfToken() });
});

app.post('/process', csrfProtection, (req, res) => {
  // Procesar formulario
});

CORS Seguro

import cors from 'cors';

const corsOptions = {
  origin: ['https://example.com'],
  credentials: true,
  optionsSuccessStatus: 200
};

app.use(cors(corsOptions));

Checklist de Seguridad

  1. ✅ HTTPS en producción
  2. ✅ Validar y sanitizar inputs
  3. ✅ Usar prepared statements
  4. ✅ Hash passwords con bcrypt
  5. ✅ Implementar rate limiting
  6. ✅ Configurar headers de seguridad
  7. ✅ Mantener dependencias actualizadas
  8. ✅ Implementar logging
  9. ✅ Usar JWT correctamente
  10. ✅ Proteger contra XSS y CSRF

Conclusión

La seguridad no es opcional. Implementa estas prácticas desde el inicio y mantente actualizado con las últimas vulnerabilidades y parches.