CORS
Concepto General
CORS (Cross-Origin Resource Sharing) es un mecanismo de seguridad que controla cómo los recursos de un sitio web pueden ser solicitados desde otro dominio distinto al de origen. Se implementa mediante cabeceras HTTP que indican qué dominios, métodos y cabeceras están permitidos al realizar peticiones entre orígenes.
Su objetivo principal es evitar accesos no autorizados o fugas de datos al consumir APIs desde navegadores, manteniendo la integridad del Backend y la protección de los usuarios en el contexto de ciberseguridad.
Orígenes
El origen se define como la combinación de protocolo, dominio y puerto.
Dos URLs pertenecen al mismo origen solo si los tres componentes coinciden exactamente.
Ejemplo:
https://api.misitio.com:443yhttps://api.misitio.com→ mismo origenhttps://app.misitio.comyhttps://api.misitio.com→ distinto origenhttp://localhost:3000yhttps://localhost:3000→ distinto origen
Cuando una aplicación cliente intenta acceder a recursos desde un origen diferente, el navegador evalúa las cabeceras CORS del servidor antes de permitir o bloquear la solicitud.
Cabeceras HTTP
Las cabeceras CORS determinan las reglas de acceso:
Access-Control-Allow-Origin: especifica qué origen puede acceder (*para todos, o una URL específica).Access-Control-Allow-Methods: lista de métodos HTTP permitidos (GET,POST,PUT,DELETE, etc.).Access-Control-Allow-Headers: define las cabeceras personalizadas aceptadas por el servidor.Access-Control-Allow-Credentials: indica si las cookies o credenciales están permitidas.Access-Control-Max-Age: tiempo en segundos que el navegador puede almacenar la política CORS en caché.
Ejemplo de Respuesta del Servidor
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://frontend.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true
`
Librería cors en Backend
En entornos como Node.js o Express.js, la librería cors simplifica la configuración mediante middleware.
Instalación
npm install cors
Uso Básico
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors());
Este ejemplo permite el acceso desde cualquier origen (*), lo cual puede ser útil para desarrollo pero no se recomienda en producción.
Configuración Personalizada
const corsOptions = {
origin: 'https://frontend.com',
methods: ['GET', 'POST'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true
};
app.use(cors(corsOptions));
Whitelist de Orígenes
Para mayor seguridad, puede definirse una lista blanca (whitelist) de dominios permitidos.
const whitelist = ['https://frontend.com', 'https://admin.frontend.com'];
const corsOptions = {
origin: (origin, callback) => {
if (!origin || whitelist.includes(origin)) {
callback(null, true);
} else {
callback(new Error('No autorizado por CORS'));
}
}
};
app.use(cors(corsOptions));
Esta configuración evalúa el origen de cada solicitud y solo permite los que estén en la lista.
Casos Prácticos
- Entorno local: permitir
http://localhostyhttp://127.0.0.1para desarrollo. - APIs públicas: configurar
Access-Control-Allow-Origin: *solo si no se manejan credenciales. - Producción: utilizar whitelist y credenciales solo cuando sea necesario.
Buenas Prácticas de Seguridad
- No usar
*enAccess-Control-Allow-Originsi se manejan cookies o tokens. - Validar los orígenes en el servidor, no confiar en el cliente.
- Registrar los intentos fallidos de acceso para auditoría.
- Comprobar configuraciones CORS en entornos de staging antes del despliegue.
Errores Comunes
- Bloqueo de navegador: ocurre cuando el servidor no devuelve las cabeceras adecuadas.
- Preflight request fallida: error en la respuesta al método
OPTIONS. - Cabeceras ausentes: olvidar incluir
Access-Control-Allow-Headerscuando se usan cabeceras personalizadas.
Diagnóstico y Depuración
- Usar herramientas de red del navegador (pestaña Network) para ver las cabeceras.
- Revisar el log del servidor para detectar rechazos de origen.
- Probar con
curloPostmanpara verificar manualmente las respuestas.
Ejemplo de prueba con curl
curl -I -X OPTIONS https://api.misitio.com -H "Origin: https://frontend.com"
Esto permite inspeccionar las cabeceras de respuesta CORS sin depender del navegador.
CORS Avanzado y Casos de Implementación
Profundización Técnica
CORS no solo gestiona peticiones simples; también regula las llamadas preflight, las cuales se ejecutan automáticamente antes de una solicitud principal cuando se cumplen ciertas condiciones (por ejemplo, métodos distintos de GET o POST, o cabeceras personalizadas).
Solicitudes Preflight
El navegador envía una solicitud OPTIONS al servidor para verificar si el origen, método y cabeceras están permitidos.
Ejemplo de Flujo Preflight
- Cliente envía:
OPTIONS /api/recurso HTTP/1.1
Origin: https://frontend.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type
`
- Servidor responde:
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://frontend.com
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 3600
Si la respuesta cumple las condiciones CORS, el navegador procede con la solicitud real (POST).
Integración con APIs REST y GraphQL
En arquitecturas modernas, especialmente con microservicios o APIs distribuidas, la correcta configuración CORS es esencial para el consumo desde clientes SPA o móviles.
Ejemplo REST
- Backend en
https://api.misitio.com - Frontend en
https://app.misitio.com
El backend debe responder con:
Access-Control-Allow-Origin: https://app.misitio.com
Ejemplo GraphQL
app.use(
'/graphql',
cors({ origin: 'https://frontend.com', credentials: true }),
express.json(),
expressMiddleware(schema)
);
Esto permite peticiones autenticadas de un dominio controlado sin exponer credenciales a otros orígenes.
CORS en Frontend
Aunque el control principal recae en el servidor, el cliente puede adaptarse a los requisitos del servidor:
- Definir el
modeenfetch:
fetch('https://api.misitio.com/datos', { mode: 'cors' });
- Incluir credenciales si el servidor lo permite:
fetch('https://api.misitio.com/secure', {
mode: 'cors',
credentials: 'include'
});
Estas configuraciones dependen del Access-Control-Allow-Credentials y el dominio autorizado.
CORS y Autenticación
Cuando se usan tokens JWT o sesiones, la configuración CORS se vuelve crítica:
- JWT: los tokens se envían en la cabecera
Authorization. El servidor debe incluir esta cabecera enAccess-Control-Allow-Headers. - Cookies de sesión: requieren
credentials: truey un origen explícito (no*).
Ejemplo de backend seguro:
app.use(
cors({
origin: 'https://frontend.com',
credentials: true,
allowedHeaders: ['Authorization', 'Content-Type']
})
);
CORS en Nginx y Apache
CORS también puede configurarse a nivel de proxy o servidor web.
Nginx
location /api/ {
add_header 'Access-Control-Allow-Origin' 'https://frontend.com';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type';
if ($request_method = OPTIONS) {
return 204;
}
}
Apache
<Directory "/var/www/api">
Header set Access-Control-Allow-Origin "https://frontend.com"
Header set Access-Control-Allow-Methods "GET,POST,OPTIONS"
Header set Access-Control-Allow-Headers "Authorization,Content-Type"
</Directory>
CORS y Reverse Proxy
En arquitecturas donde un reverse proxy (como Nginx o Traefik) se encarga de enrutar peticiones, CORS puede manejarse directamente en el proxy, aliviando la carga del Backend. Esto facilita aplicar políticas centralizadas para múltiples microservicios.
Testing y Validación
Herramientas útiles:
- Postman y Insomnia para probar cabeceras manualmente.
- curl para solicitudes controladas.
- Extensiones de navegador como Allow CORS: Access-Control-Allow-Origin (solo para pruebas, nunca en producción).
Automatización en testing:
import request from 'supertest';
import app from '../app';
test('Permite solicitudes desde origen válido', async () => {
const res = await request(app)
.get('/api/data')
.set('Origin', 'https://frontend.com');
expect(res.headers['access-control-allow-origin']).toBe('https://frontend.com');
});
Estrategias Avanzadas
- Dynamic Origin Handling: permitir orígenes basados en configuración o entorno.
- Rate Limiting por Origen: limitar tráfico según el dominio para mitigar abusos.
- Registro de Solicitudes CORS: almacenar intentos de acceso no autorizados para análisis de seguridad.
Conclusión Técnica
CORS es una capa crítica en la arquitectura web moderna que conecta seguridad, accesibilidad y diseño de APIs. Su mala configuración puede exponer vulnerabilidades o impedir la comunicación legítima entre servicios. La clave está en aplicar políticas precisas, no genéricas, integradas dentro de un contexto seguro de Backend, ciberseguridad y despliegue.
CORS: Casos Avanzados, Configuraciones Complejas y Escenarios Especiales
CORS en Microservicios y Arquitecturas Distribuidas
En entornos basados en microservicios, el control de CORS puede descentralizarse o centralizarse según la topología:
- Centralizado (en gateway o API Gateway): el control CORS se gestiona en un punto de entrada común, simplificando la configuración.
- Descentralizado (en cada microservicio): cada servicio define su propia política, útil si hay diferentes dominios o niveles de acceso.
Ejemplo con Express.js y API Gateway:
gateway.use('/api/users', cors({ origin: 'https://app.frontend.com' }), usersService);
gateway.use('/api/payments', cors({ origin: 'https://admin.frontend.com' }), paymentsService);
`
CORS en WebSockets
Aunque CORS no se aplica directamente a WebSockets (ws:// o wss://), el concepto de origen confiable sigue siendo relevante.
Los navegadores solo permiten conexiones WebSocket al mismo origen o a dominios que implementen medidas equivalentes de validación en el handshake.
Configuración típica:
const wsServer = new WebSocketServer({
verifyClient: (info, done) => {
const origin = info.origin;
const allowed = ['https://frontend.com', 'https://admin.frontend.com'];
if (allowed.includes(origin)) done(true);
else done(false, 403, 'Origin not allowed');
}
});
CORS en Aplicaciones Móviles y pwa
Las aplicaciones móviles híbridas (por ejemplo, con capacitor o Cordova) no siempre ejecutan restricciones CORS, ya que operan fuera del contexto del navegador. Sin embargo, en pwa o entornos que usan Service Workers, las políticas CORS siguen aplicándose para proteger las respuestas cacheadas o interceptadas.
Ejemplo de manejo con fetch y Service Worker:
self.addEventListener('fetch', event => {
event.respondWith(
fetch(event.request, { mode: 'cors' })
.then(response => response)
.catch(() => caches.match(event.request))
);
});
CORS y CDN
Cuando los recursos (imágenes, fuentes, scripts) se sirven desde un CDN, es esencial que las cabeceras CORS estén configuradas correctamente para permitir su uso desde otros dominios.
Ejemplo en AWS S3:
<CORSConfiguration>
<CORSRule>
<AllowedOrigin>https://app.frontend.com</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedHeader>*</AllowedHeader>
<ExposeHeader>Content-Length</ExposeHeader>
</CORSRule>
</CORSConfiguration>
Esto habilita el uso de recursos estáticos en un frontend alojado en otro dominio.
CORS y HTTP/2 o HTTP/3
Con protocolos modernos, las cabeceras CORS siguen funcionando igual, pero su interpretación puede verse afectada por:
- Multiplexación de peticiones.
- Cabeceras pseudo (
:method,:path, etc.). - Compresión y priorización de streams.
En estos contextos, el control CORS sigue siendo una capa lógica sobre HTTP, no una limitación técnica del protocolo.
CORS en Cloudflare, AWS API Gateway y Azure API Management
Cloudflare
Permite definir reglas de cabeceras personalizadas en su panel o mediante Transform Rules:
Access-Control-Allow-Origin: https://frontend.com
Access-Control-Allow-Methods: GET, POST, OPTIONS
AWS API Gateway
En APIs gestionadas, las políticas CORS se definen por recurso:
{
"Access-Control-Allow-Origin": "'https://frontend.com'",
"Access-Control-Allow-Methods": "'GET,POST,OPTIONS'"
}
Azure API Management
Usa Inbound Policies XML:
<inbound>
<base />
<cors>
<allowed-origins>
<origin>https://frontend.com</origin>
</allowed-origins>
<allowed-methods>
<method>GET</method>
<method>POST</method>
</allowed-methods>
</cors>
</inbound>
CORS y SSE (Server-Sent Events)
Al usar event streams, el navegador sigue respetando CORS. El servidor debe enviar cabeceras adecuadas antes de abrir el stream.
Ejemplo:
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Access-Control-Allow-Origin': 'https://frontend.com',
'Cache-Control': 'no-cache',
Connection: 'keep-alive'
});
CORS en Testing y Automatización QA
Las pruebas automáticas deben incluir escenarios CORS para evitar bloqueos en producción:
- Simular orígenes distintos con herramientas como
supertestoplaywright. - Incluir pruebas de preflight y validación de credenciales.
- Asegurar que los endpoints de error también devuelvan cabeceras CORS válidas.
Ejemplo con Playwright:
test('bloquea origen no autorizado', async ({ request }) => {
const res = await request.get('https://api.misitio.com/data', {
headers: { Origin: 'https://malicious.com' }
});
expect(res.status()).toBe(403);
});
CORS y OAuth2 / OpenID Connect
Durante los flujos de autenticación (especialmente Authorization Code Flow), los redireccionamientos entre dominios requieren configuraciones CORS y de redirect URI sincronizadas. Si no se gestionan correctamente, el navegador bloqueará las respuestas o tokens.
Recomendaciones:
- Mantener los
redirect_uriregistrados en el proveedor de identidad. - Usar dominios consistentes en frontend y backend (por ejemplo, subdominios compartidos).
- No exponer tokens en respuestas sin CORS adecuado.
CORS en Serverless Functions
En plataformas como Vercel, Netlify Functions o AWS Lambda, CORS debe configurarse manualmente en cada función o mediante middleware global.
Ejemplo en Vercel:
export default function handler(req, res) {
res.setHeader('Access-Control-Allow-Origin', 'https://frontend.com');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
if (req.method === 'OPTIONS') return res.status(204).end();
res.status(200).json({ message: 'OK' });
}
Monitoreo y Auditoría
Para garantizar seguridad continua:
- Analizar logs de acceso rechazado.
- Implementar métricas sobre orígenes más frecuentes.
- Integrar alertas cuando se detecten solicitudes repetidas de orígenes desconocidos.
Integración con herramientas de observabilidad como Grafana o Elastic Stack para visualizar tráfico bloqueado por CORS.
Enfoque de Diseño Seguro
- Definir políticas CORS desde el diseño inicial del sistema.
- Mantener consistencia entre entornos (dev, staging, prod).
- Integrar CORS en revisiones de seguridad y pentesting.
- Documentar claramente las políticas de acceso en la API.
En resumen, hemos cubierto el espectro completo de CORS:
- Fundamentos técnicos y cabeceras.
- Implementación en Backend, proxies y nubes.
- Integraciones con protocolos y arquitecturas modernas.
- Estrategias de seguridad, auditoría y pruebas automatizadas.
Con esta extensión, el tema CORS queda completamente desarrollado en todos sus niveles prácticos, conceptuales y de aplicación real.
¿Te gusta este contenido? Suscríbete vía RSS