CORS (Cross-Origin Resource Sharing) es un mecanismo de seguridad del navegador que controla si una página web que se ejecuta en un origen tiene permiso para solicitar recursos de un origen diferente.
TL;DR CORS lo aplican los navegadores, no los servidores. Cuando JavaScript en
app.example.comobtiene datos deapi.other.com, el navegador verifica si el servidor de la API permite explícitamente esta solicitud de origen cruzado examinando los headers de respuesta HTTP — principalmenteAccess-Control-Allow-Origin. Si el header no está presente o no coincide, el navegador bloquea la respuesta, aunque el servidor la haya procesado con éxito. Los errores de CORS son bloqueos del lado del cliente, no fallos del lado del servidor. La solución siempre es agregar los headers de respuesta correctos en el servidor (o edge) que recibe la solicitud.
¿Qué es CORS?
CORS (Cross-Origin Resource Sharing) es un estándar W3C implementado por todos los navegadores modernos. Extiende la política de mismo origen — la regla que dice que una página web solo puede acceder a recursos del mismo origen exacto (protocolo + dominio + puerto) — permitiendo que los servidores declaren explícitamente qué otros orígenes tienen permiso de acceder a sus recursos.
Un origen se define por tres componentes:
- Protocolo —
https://vshttp:// - Dominio —
example.comvsapi.example.com - Puerto —
:443vs:3000
Dos URLs tienen el mismo origen solo si los tres coinciden exactamente. https://app.example.com y https://api.example.com son orígenes diferentes porque el subdominio difiere.
Por qué existe CORS
Sin la política de mismo origen, cualquier sitio web malicioso podría usar JavaScript para hacer solicitudes a tu banco, correo electrónico o cualquier servicio autenticado — y el navegador enviaría tus cookies de sesión automáticamente. El navegador recibiría y expondría la respuesta al script del atacante.
La política de mismo origen evita esto bloqueando las lecturas de origen cruzado. CORS luego proporciona una forma controlada para que los servidores opten por el intercambio de origen cruzado — de forma selectiva y explícita.
Cómo funciona CORS
Solicitudes simples
Una solicitud simple es una solicitud de origen cruzado que cumple todas estas condiciones:
- El método es
GET,POSToHEAD - Los headers son solo
Accept,Accept-Language,Content-LanguageoContent-Type(con valorapplication/x-www-form-urlencoded,multipart/form-dataotext/plain)
Para solicitudes simples, el navegador envía la solicitud directamente e incluye un header Origin. El servidor debe responder con Access-Control-Allow-Origin que coincida con el origen de la solicitud. Si no lo hace, el navegador bloquea la respuesta para que no llegue a JavaScript.
Solicitud:GET /data HTTP/1.1Origin: https://app.example.com
Respuesta:Access-Control-Allow-Origin: https://app.example.comSolicitudes preflight
Para solicitudes que no cumplen los criterios de solicitud simple — como PUT, DELETE, PATCH, o solicitudes con headers personalizados como Authorization — el navegador primero envía una solicitud preflight usando el método OPTIONS.
OPTIONS /data HTTP/1.1Origin: https://app.example.comAccess-Control-Request-Method: PUTAccess-Control-Request-Headers: Authorization, Content-TypeEl servidor debe responder al preflight con los headers CORS apropiados antes de que el navegador envíe la solicitud real:
HTTP/1.1 204 No ContentAccess-Control-Allow-Origin: https://app.example.comAccess-Control-Allow-Methods: GET, POST, PUT, DELETEAccess-Control-Allow-Headers: Authorization, Content-TypeAccess-Control-Max-Age: 86400Si el preflight falla, el navegador nunca envía la solicitud real.
Headers de respuesta CORS
| Header | Propósito | Valor de ejemplo |
|---|---|---|
Access-Control-Allow-Origin | Especifica qué origen(es) puede(n) acceder al recurso | https://app.example.com o * |
Access-Control-Allow-Methods | Métodos HTTP permitidos para solicitudes de origen cruzado | GET, POST, PUT, DELETE |
Access-Control-Allow-Headers | Headers de solicitud permitidos | Authorization, Content-Type |
Access-Control-Allow-Credentials | Si se incluyen cookies/credenciales | true |
Access-Control-Max-Age | Cuánto tiempo (en segundos) se puede almacenar en caché el resultado del preflight | 86400 |
Access-Control-Expose-Headers | Qué headers de respuesta puede leer JavaScript | X-Request-ID |
Regla crítica: No puedes usar Access-Control-Allow-Origin: * junto con Access-Control-Allow-Credentials: true. Los navegadores rechazan esta combinación. Debes especificar el origen exacto cuando hay credenciales involucradas.
Errores CORS comunes y soluciones
| Mensaje de error | Causa | Solución |
|---|---|---|
No 'Access-Control-Allow-Origin' header is present | El servidor no devuelve el header CORS | Agrega Access-Control-Allow-Origin a la respuesta |
The value of 'Access-Control-Allow-Origin' does not equal the supplied origin | El valor del header no coincide con el origen solicitante | Refleja dinámicamente el Origin de la solicitud o lista todos los orígenes permitidos |
Response to preflight request doesn't pass access control check | La solicitud OPTIONS de preflight no se maneja | Agrega un handler de OPTIONS que devuelva los headers CORS apropiados |
Credential flag is true but Access-Control-Allow-Credentials is not true | Se enviaron credenciales pero el servidor no las permitió | Agrega Access-Control-Allow-Credentials: true y especifica el origen exacto |
Method PUT is not allowed | Método ausente en Access-Control-Allow-Methods | Agrega el método requerido al header de métodos permitidos |
Request header 'Authorization' is not allowed | Header personalizado no listado en Access-Control-Allow-Headers | Agrega el header a Access-Control-Allow-Headers |
Riesgos de seguridad de CORS
Wildcard con credenciales
Usar Access-Control-Allow-Origin: * es seguro para APIs públicas que no usan cookies ni tokens de sesión. Nunca combines * con Access-Control-Allow-Credentials: true — esto expone datos autenticados a cualquier origen.
Reflejar el header Origin sin validación
Algunas implementaciones reflejan ciegamente el header Origin de la solicitud como Access-Control-Allow-Origin. Si haces esto sin validar contra una lista de permisos, permites que cualquier origen acceda a tu API. Siempre valida el valor de Origin contra una lista de permisos antes de reflejarlo.
Origen null
El valor Origin: null es enviado por los navegadores para solicitudes desde URLs file:// o iframes en sandbox. Nunca incluyas null como origen permitido — puede ser explotado.
Preguntas frecuentes
¿Qué es un error CORS? Un error CORS es un bloqueo impuesto por el navegador en una respuesta HTTP de origen cruzado. Significa que JavaScript en un origen intentó leer una respuesta de un origen diferente, pero la respuesta del servidor no incluyó los headers que otorgan permiso. La solicitud en sí llegó al servidor — el navegador solo bloqueó la respuesta para que no fuera accesible al script.
¿CORS aplica a solicitudes servidor a servidor? No. CORS solo lo aplican los navegadores. Cuando tu servidor backend llama a otra API, no hay aplicación de CORS — la llamada pasa sin importar qué. CORS solo aplica cuando JavaScript ejecutándose en un navegador hace una solicitud de origen cruzado.
¿Cuál es la diferencia entre CORS y la política de mismo origen? La política de mismo origen es la regla de seguridad predeterminada del navegador que bloquea las lecturas de origen cruzado. CORS es el mecanismo que permite a los servidores relajar selectivamente esa restricción devolviendo headers HTTP específicos. CORS no evita la política de mismo origen — proporciona una forma estandarizada para que los servidores opten por el acceso de origen cruzado.
¿Puedo deshabilitar CORS? No puedes deshabilitar CORS en los navegadores — se aplica a nivel del navegador. Lo que puedes hacer es configurar tu servidor para devolver los headers CORS correctos que permitan tus solicitudes de origen cruzado específicas. Las extensiones de navegador que “deshabilitan CORS” solo funcionan interceptando respuestas e inyectando los headers faltantes del lado del cliente.
¿Qué significa Access-Control-Allow-Origin: *? Significa que cualquier origen tiene permitido leer la respuesta. Esto es apropiado para APIs completamente públicas (sin autenticación, sin cookies). Nunca uses * para APIs que requieren autenticación o acceso a datos del usuario.
¿Qué es una solicitud preflight? Una solicitud preflight es una solicitud OPTIONS automática que el navegador envía antes de ciertas solicitudes de origen cruzado para preguntarle al servidor qué permite. El servidor debe responder con headers CORS aprobando el método, los headers y el origen antes de que el navegador envíe la solicitud real. Las respuestas de preflight se pueden almacenar en caché usando Access-Control-Max-Age.
¿Cómo corrijo errores CORS en desarrollo? En desarrollo, el enfoque más común es configurar tu servidor de API local para devolver Access-Control-Allow-Origin: http://localhost:3000 (la URL de tu servidor de desarrollo frontend). No uses una extensión de navegador para omitir CORS en desarrollo — oculta problemas reales que aparecerán en producción.
¿Puede un CDN o edge manejar CORS por mí? Sí. Puedes configurar headers CORS en el edge — agregando Access-Control-Allow-Origin y otros headers a las respuestas antes de que lleguen al navegador, sin modificar el servidor de origen. Esto es útil para APIs de terceros que no controlas, o para centralizar la política CORS en múltiples orígenes.