Skip to content
IsSafeSite
2 min de lecturaIsSafeSite Team

CORS explicado: configuración segura de origen cruzado para sitios modernos

CORS se malinterpreta tan a menudo como se configura mal. Esto es lo que hacen realmente las cabeceras, la trampa del comodín con credenciales y cómo asegurar una API correctamente.

CORSAPIsEndurecimiento

El intercambio de recursos de origen cruzado (CORS) es donde muchos equipos conocen por primera vez la seguridad del navegador, normalmente porque algo se rompió y el primer resultado de búsqueda decía «permite todos los orígenes y ya». Ese arreglo funciona y, en silencio, se convierte en una vulnerabilidad. Esto es lo que CORS hace de verdad y cómo configurarlo sin abrir tu API a todos los sitios de internet.

Qué controla CORS en realidad

CORS no es un control de acceso del lado del servidor. Es un mecanismo del navegador que decide si el JavaScript que se ejecuta en el origen A puede *leer* una respuesta del origen B. No hace nada para detener una petición directa de curl, de un servidor o de un script que ignora el navegador. Trátalo como una barrera para clientes de navegador y mantén la autorización real en el servidor de todas formas.

La trampa del comodín con credenciales

La configuración de CORS más peligrosa es reflejar el origen de la petición y, además, permitir credenciales:

Access-Control-Allow-Origin: https://evil.example
Access-Control-Allow-Credentials: true

Si tu servidor devuelve cualquier Origin que recibe y pone Allow-Credentials: true, cualquier sitio puede hacer peticiones autenticadas como tu usuario conectado y leer la respuesta. El navegador prohíbe el * literal junto con credenciales por este motivo, pero reflejar el origen salta esa protección y vuelve a crear el agujero.

Una configuración correcta y restrictiva

Compara el origen entrante con una lista de permitidos explícita y solo entonces devuélvelo:

const allowed = new Set([
  'https://app.example.com',
  'https://admin.example.com',
]);

const origin = req.headers.get('origin');
if (origin && allowed.has(origin)) {
  res.setHeader('Access-Control-Allow-Origin', origin);
  res.setHeader('Vary', 'Origin');
  res.setHeader('Access-Control-Allow-Credentials', 'true');
}

La cabecera Vary: Origin es fácil de olvidar e importante: sin ella, una caché puede servir la cabecera de permiso de un origen a otro distinto.

Limita también métodos y cabeceras

Access-Control-Allow-Origin es solo la mitad de la política. Mantén el resto ajustado:

  • Permite solo los métodos que usa el endpoint, p. ej. Access-Control-Allow-Methods: GET, POST.
  • Permite solo las cabeceras de petición que esperas, no una lista genérica.
  • Pon un Access-Control-Max-Age razonable para que se cacheen las peticiones de preflight.
  • Nunca combines Allow-Origin: * con Allow-Credentials: true.

Cuándo un comodín sí está bien

Una API de verdad pública, sin autenticación y de solo lectura —un feed de tipos de cambio, un endpoint de estado público— puede usar Access-Control-Allow-Origin: * con seguridad, precisamente porque no hay credenciales ni nada privado que filtrar. El peligro siempre es la apertura tipo * combinada con autenticación.

Pruébalo desde un contexto de origen cruzado real

CORS se comporta distinto para peticiones simples y para las que llevan preflight, así que prueba ambas desde un navegador en otro origen, no solo con curl (que ignora CORS por completo). Un análisis comprueba tus cabeceras de respuesta CORS automáticamente junto al resto de tus comprobaciones de seguridad; para ver cómo encajan los hallazgos de CORS en una lista priorizada de correcciones, lee Cómo leer un informe de análisis de seguridad web.

Convierte estas comprobaciones en un informe de análisis de tu propio sitio.

Ejecuta un análisis gratuito y obtén hallazgos priorizados y accionables en unos 30 segundos.

Analizar mi sitio

Sigue leyendo