OWASP Top 10 para SaaS en 2025
El OWASP Top 10 se actualiza periódicamente y cada versión refleja las amenazas reales. Para SaaS multi-tenant — ERPs, CRMs, plataformas de gestión — algunas vulnerabilidades son especialmente críticas porque un error puede exponer datos de múltiples clientes.
A01: Broken Access Control
La vulnerabilidad #1 en 2025. El 94% de las aplicaciones tienen alguna falla de control de acceso.
El error más común en SaaS multi-tenant:``python
❌ MAL: Solo verifica autenticación, no autorización
@router.get("/invoices/{invoice_id}")
async def get_invoice(invoice_id: uuid.UUID, user = Depends(get_current_user)):
return await invoice_repo.get(invoice_id) # Cualquier usuario puede ver cualquier factura
✅ BIEN: Verifica que el recurso pertenece al usuario
@router.get("/invoices/{invoice_id}") async def get_invoice(invoice_id: uuid.UUID, user = Depends(get_current_user)): invoice = await invoice_repo.get(invoice_id) if invoice.organization_id != user.organization_id: raise HTTPException(403, "Acceso denegado") return invoice `
A02: Cryptographic Failures
Contraseñas hasheadas con MD5, tokens JWT sin expiración, comunicación sin TLS.
JWT con expiración correcta:
`python
def create_access_token(user_id: str) -> str:
payload = {
"sub": user_id,
"exp": datetime.utcnow() + timedelta(hours=1), # Siempre con expiración
"iat": datetime.utcnow(),
"jti": str(uuid.uuid4()), # ID único para poder invalidar
}
return jwt.encode(payload, SECRET_KEY, algorithm="HS256")
`
A03: Injection
SQL injection sigue siendo relevante incluso con ORMs.
`python
❌ MAL: Query raw sin parametrizar
query = f"SELECT * FROM users WHERE email = '{email}'"
✅ BIEN: Siempre parametrizado
stmt = select(User).where(User.email == email)
`
A04: Insecure Design
Diseño sin considerar la seguridad desde el inicio. El ejemplo más común: endpoints que devuelven más datos de los necesarios.
A05: Security Misconfiguration
Debug mode en producción, credenciales por defecto, headers de seguridad faltantes.
`python
Headers de seguridad obligatorios
@app.middleware("http")
async def security_headers(request, call_next):
response = await call_next(request)
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "DENY"
response.headers["Strict-Transport-Security"] = "max-age=31536000"
return response
`
A07: Authentication Failures
Rate limiting en login, bloqueo de cuentas, y logs de intentos fallidos son obligatorios.
A09: Security Logging Failures
Si no registras los eventos de seguridad, no puedes detectar ataques en curso.
`python
async def audit_log(user_id, action, resource, ip):
await db.execute(insert(AuditLog).values(
user_id=user_id, action=action,
resource=resource, ip=ip,
timestamp=datetime.utcnow()
))
``
Conclusión
La seguridad no es un feature — es una capa fundamental que debe estar presente desde la arquitectura inicial. En Visionary AI Group incluimos auditoría OWASP básica en cada proyecto que entregamos, sin costo adicional.
¿Te fue útil?
Compártelo con tu equipo
Favio Villanueva
CEO & Arquitecto de Software
Arquitecto de software con +8 años de experiencia construyendo sistemas SaaS escalables. Fundador de Visionary AI Group, operando en 12 países.