Qué es OWASP Top 10?
OWASP (Open Web Application Security Project) pública periodicamente una lista de las 10 vulnerabilidades más críticas en aplicaciones web. Es el estandar de referencia para seguridad web en la industria.
Esta guia cubre cada vulnerabilidad con ejemplos de código vulnerable y su versión segura.
A01: Broken Access Control
El control de acceso roto es la vulnerabilidad número uno. Ocurre cuando los usuarios pueden actuar fuera de sus permisos.
Ejemplos comunes
- Acceder a cuentas de otros usuarios cambiando el ID en la URL
- Elevar privilegios de usuario normal a admin
- Manipular tokens o cookies para saltarse verificaciones
Código vulnerable
// VULNERABLE: no verifica que el usuario sea el dueno del recurso
app.get('/api/users/:id/profile', async (req, res) => {
const profile = await db.getProfile(req.params.id);
res.json(profile); // Cualquier usuario puede ver cualquier perfil
});Código seguro
// SEGURO: verificar autorización
app.get('/api/users/:id/profile', authenticate, async (req, res) => {
const requestedId = req.params.id;
const authenticatedUserId: string = req.user.id;
if (requestedId !== authenticatedUserId && !req.user.isAdmin) {
return res.status(403).json({ error: 'No autorizado' });
}
const profile = await db.getProfile(requestedId);
res.json(profile);
});Prevencion
- Denegar acceso por defecto
- Implementar control de acceso en el servidor, nunca solo en el frontend
- Registrar y alertar sobre fallas de control de acceso
- Limitar rate de peticiones a APIs
A02: Cryptographic Failures
Fallas criptograficas incluyen transmitir datos sensibles en texto plano, usar algoritmos obsoletos o gestionar mal las claves.
Errores comunes
// VULNERABLE: hashear con MD5 o SHA1
import crypto from 'crypto';
const hash = crypto.createHash('md5').update(password).digest('hex');
// VULNERABLE: almacenar datos sensibles sin cifrar
localStorage.setItem('creditCard', '4532-1234-5678-9012');
// VULNERABLE: transmitir datos sensibles en la URL
fetch(`/api/reset-password?token=${token}&newPassword=${password}`);Solucion correcta
- Usa bcrypt, scrypt o Argon2 para passwords
- Cifra datos sensibles en reposo con AES-256
- Usa HTTPS para todo el trafico
- No transmitas datos sensibles en URLs o query parameters
- Genera claves y tokens con funciones criptograficamente seguras
A03: Injection
Las inyecciones ocurren cuando datos no confiables se envian a un interprete como parte de un comando o consulta.
Tipos de inyección
| Tipo | Vector | Ejemplo |
|---|---|---|
| SQL Injection | Consultas SQL | ' OR 1=1 -- |
| NoSQL Injection | Consultas MongoDB | {"$gt": ""} |
| Command Injection | Comandos del SO | ; rm -rf / |
| LDAP Injection | Consultas LDAP | `)(uid=))( |
| Template Injection | Motores de plantillas | {{constructor.constructor('return this')()}} |
Prevencion universal
- Usar consultas parametrizadas siempre
- Validar y sanitizar todo input
- Usar ORMs que parametricen automaticamente
- Aplicar el principio de mínimo privilegio en la base de datos
A04: Insecure Design
El diseño inseguro se refiere a fallas fundamentales en la arquitectura de la aplicación que no se pueden solucionar con mejor implementación.
Ejemplo
Flujo de recuperacion de password INSEGURO:
1. Usuario pide reset
2. Se envia pregunta de seguridad (fácil de adivinar)
3. Se muestra la password en la pantalla
Flujo SEGURO:
1. Usuario pide reset con su email
2. Se genera un token criptografico con expiracion (30 min)
3. Se envia link único al email registrado
4. El token es de un solo uso y se invalida al usarsePrincipios de diseño seguro
- Modela las amenazas antes de escribir código
- Aplica defense in depth (multiples capas de seguridad)
- Separa responsabilidades y permisos
- Falla de forma segura (deny by default)
A05: Security Misconfiguration
La configuración incorrecta es una de las vulnerabilidades más frecuentes y fáciles de explotar.
Checklist de configuración
// Verificar configuración de seguridad en Express
interface SecurityConfig {
helmet: boolean;
cors: {
origin: string[];
credentials: boolean;
};
rateLimit: {
windowMs: number;
max: number;
};
production: {
stackTraces: boolean;
debugMode: boolean;
defaultCredentials: boolean;
};
}
const secureConfig: SecurityConfig = {
helmet: true,
cors: {
origin: ['https://tudominio.com'], // NO usar '*'
credentials: true
},
rateLimit: {
windowMs: 15 * 60 * 1000,
max: 100
},
production: {
stackTraces: false, // NUNCA en producción
debugMode: false, // NUNCA en producción
defaultCredentials: false // Cambiar SIEMPRE
}
};A06: Vulnerable and Outdated Components
Usar dependencias con vulnerabilidades conocidas es como dejar la puerta abierta.
Estrategia de mitigacion
# Auditar dependencias regularmente
npm audit
# Auditar solo producción
npm audit --production
# Corregir automaticamente lo posible
npm audit fix
# Ver dependencias desactualizadas
npm outdated
# Herramientas automaticas
# Activar Dependabot o Renovate en tu repositorioPolitica recomendada
- Auditar dependencias en cada build de CI
- Actualizar dependencias con vulnerabilidades críticas en 24 horas
- Actualizar dependencias con vulnerabilidades altas en 1 semana
- Revisar dependencias transitivas (las que tus dependencias usan)
A07: Identification and Authentication Failures
Las fallas de autenticación permiten a los atacantes comprometer passwords, tokens o explotar fallas de implementación.
Requisitos minimos de password
interface PasswordValidation {
isValid: boolean;
errors: string[];
}
function validatePassword(password: string): PasswordValidation {
const errors: string[] = [];
if (password.length < 12) {
errors.push('Minimo 12 caracteres');
}
if (password.length > 128) {
errors.push('Maximo 128 caracteres');
}
if (!/[A-Z]/.test(password)) {
errors.push('Al menos una mayuscula');
}
if (!/[a-z]/.test(password)) {
errors.push('Al menos una minuscula');
}
if (!/[0-9]/.test(password)) {
errors.push('Al menos un número');
}
if (!/[^A-Za-z0-9]/.test(password)) {
errors.push('Al menos un caracter especial');
}
return { isValid: errors.length === 0, errors };
}A08: Software and Data Integrity Failures
Ocurre cuando el código o la infraestructura no protegen contra violaciones de integridad: pipelines CI/CD inseguros, actualizaciones sin verificación, dependencias de CDN sin integrity checks.
Subresource Integrity (SRI)
<!-- INSEGURO: cargar script de CDN sin verificación -->
<script src="https://cdn.example.com/lib.js"></script>
<!-- SEGURO: con SRI, el navegador verifica el hash -->
<script
src="https://cdn.example.com/lib.js"
integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxAh6VgnSY"
crossorigin="anonymous">
</script>A09: Security Logging and Monitoring Failures
Sin logs adecuados, no puedes detectar ni responder a ataques.
Qué registrar
interface SecurityLog {
timestamp: string;
event: string;
severity: 'INFO' | 'WARN' | 'ERROR' | 'CRITICAL';
userId: string | null;
ip: string;
details: Record<string, unknown>;
}
function logSecurityEvent(log: SecurityLog): void {
// Enviar a sistema de logging centralizado
console.log(JSON.stringify({
...log,
timestamp: new Date().toISOString()
}));
}
// Eventos críticos que DEBES registrar:
// - Intentos de login fallidos
// - Cambios de password/email
// - Fallas de control de acceso (403)
// - Errores de validación de input sospechosos
// - Cambios de permisos/rolesA10: Server-Side Request Forgery (SSRF)
SSRF ocurre cuando un atacante puede hacer que tu servidor envie peticiones a destinos arbitrarios.
Prevencion
// VULNERABLE: el usuario controla la URL
app.get('/api/fetch-url', async (req, res) => {
const url = req.query.url as string;
const response = await fetch(url); // Puede acceder a red interna!
res.json(await response.json());
});
// SEGURO: validar y restringir URLs
function isUrlAllowed(url: string): boolean {
try {
const parsed = new URL(url);
// Solo HTTPS
if (parsed.protocol !== 'https:') return false;
// Bloquear IPs internas
const blockedPatterns = [
/^localhost$/i,
/^127\./,
/^10\./,
/^172\.(1[6-9]|2[0-9]|3[0-1])\./,
/^192\.168\./,
/^0\./,
/^169\.254\./ // Link-local
];
if (blockedPatterns.some(p => p.test(parsed.hostname))) return false;
// Lista blanca de dominios permitidos
const allowedDomains = ['api.github.com', 'api.example.com'];
return allowedDomains.includes(parsed.hostname);
} catch {
return false;
}
}Conclusion
El OWASP Top 10 no es solo una lista: es un marco de referencia para construir aplicaciones seguras. Cada vulnerabilidad tiene contramedidas claras y probadas.
La clave esta en integrar la seguridad desde el diseño, no como un parche posterior. Usa esta guia como checklist en cada proyecto y revisa periodicamente las actualizaciones de OWASP.




Comentarios (0)
Inicia sesión para comentar