Express.js
CORS y same-origin policy
Explica la same-origin policy, preflight y configuración de CORS en Express.js, incluyendo credentials, allowlists, Vary y límites como mecanismo de seguridad.
- Última actualización
- Actualizada
- Nivel
- Fundamentos
Express.js
Explica la same-origin policy, preflight y configuración de CORS en Express.js, incluyendo credentials, allowlists, Vary y límites como mecanismo de seguridad.
CORS es una política aplicada por navegadores para decidir si una página puede leer una respuesta cross-origin. No es autenticación, autorización, firewall ni protección completa contra CSRF.
Una origin combina:
scheme + host + porthttps://app.example.com y https://api.example.com son origins distintas. La same-origin policy restringe cómo un documento interactúa con otra origin. CORS permite al servidor declarar excepciones mediante headers.
Sin CORS, una SPA alojada en una origin distinta no podría leer respuestas de la API desde JavaScript, aunque la red y autenticación funcionen.
CORS no impide que:
curl llame la APIEl servidor sigue necesitando auth, autorización, validación y rate limiting.
Algunas combinaciones de método, headers y Content-Type pueden enviarse sin preflight. El navegador después decide si expone la response al script según headers CORS.
Por eso “no hubo preflight” no significa “no hubo request”.
Para requests no simples, el navegador envía OPTIONS:
OPTIONS /orders
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type, authorizationEl servidor responde:
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 600
Vary: OriginSolo después el navegador envía la request real si la política lo permite.
import cors from 'cors';
const allowedOrigins = new Set([
'https://app.example.com',
'https://admin.example.com',
]);
app.use(cors({
origin(origin, callback) {
if (!origin) {
callback(null, false);
return;
}
callback(null, allowedOrigins.has(origin));
},
credentials: true,
methods: ['GET', 'POST', 'PATCH', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization', 'X-CSRF-Token'],
maxAge: 600,
}));Una origin ausente puede provenir de server-to-server, curl o navegación particular. Decidir false no bloquea la request en el backend; solo evita headers CORS. La auth decide acceso real.
Access-Control-Allow-Origin: *Es válido para recursos públicos sin credenciales. No puede combinarse con credentials del navegador.
No reflejes cualquier Origin:
origin: truesin una policy. Eso convierte cualquier sitio en origin permitida.
Para cookies o credenciales cross-origin:
credentials: 'include'Access-Control-Allow-Credentials: true*Si el servidor responde una origin distinta según request, caches deben separar variantes. Sin Vary: Origin, una response autorizada para una origin puede reutilizarse incorrectamente.
JavaScript no puede leer todos los headers arbitrariamente. Para uno personalizado:
Access-Control-Expose-Headers: X-Request-Id, ETagNo expongas información sensible por comodidad.
Access-Control-Max-Age reduce OPTIONS, pero una política cambiada puede tardar en reflejarse en browsers. Usa una duración razonable.
No abras * en producción porque localhost (se abre en otra pestaña) necesita acceso. Define origins por configuración validada. Evita regex amplias como *.example.com si subdominios pueden ser controlados por terceros.
Una SPA en https://admin.nicoo.dev llama https://api.nicoo.dev con cookie:
Puede aparecer en archivos locales, iframes sandboxed o redirects. No lo autorices sin un caso explícito.
El soporte puede variar. Evita redirects de OPTIONS y canonicaliza en proxy.
El navegador muestra un error CORS y oculta el body. Aplica middleware antes de rutas y error handler cuando el cliente necesita leer errores.
No usan CORS igual que fetch. Valida Origin y autentica handshake explícitamente.
Configura Vary y cache keys para no mezclar origins.
Vary: Origin.Prueba con navegador o herramienta que simule:
VarynullUn test con curl solo no reproduce enforcement del navegador.
Una whitelist estricta reduce exposición accidental, pero exige gestionar entornos y previews. CORS dinámico por tenant puede ser útil, aunque añade lookup, cache y riesgo de reflexión.
Vary: Origin es crítico con respuestas dinámicas.* no funciona con credentials?Vary: Origin?CSRF y autenticación basada en cookies analiza cómo un sitio externo puede inducir mutations usando credenciales automáticas.