Tema 14

14. CORS, cabeceras de seguridad y exposición controlada a clientes web

Cuando una API es consumida desde navegadores, entra en juego un modelo de seguridad adicional: el del propio browser. CORS y otras cabeceras relacionadas no reemplazan autenticación ni autorización, pero condicionan qué orígenes web pueden interactuar con la API y cómo se expone el servicio a clientes ejecutándose en el entorno más adversarial de todos: el navegador del usuario.

Objetivo Controlar con precisión cómo una API se expone a navegadores
Enfoque Modelo browser, CORS y cabeceras defensivas
Resultado Evitar configuraciones permisivas y falsas suposiciones de seguridad

14.1 Introducción

Muchas APIs modernas son consumidas por SPAs, dashboards, portales administrativos o integraciones web que se ejecutan en el navegador. En ese contexto, no basta con pensar en el backend; también hay que entender qué controles aplica el browser y cómo una configuración inapropiada puede abrir acceso a orígenes no previstos.

CORS suele ser malinterpretado. A veces se configura de forma demasiado abierta para “hacer que funcione”, y otras veces se le atribuyen propiedades que no tiene. El resultado son APIs que exponen más de lo necesario o equipos que creen estar protegidos por una política que en realidad no reemplaza controles de acceso reales.

Este tema explica qué resuelve CORS, qué no resuelve y cómo combinarlo con cabeceras y diseño de exposición segura para clientes web.

14.2 Qué es el modelo de mismo origen

Los navegadores aplican una política llamada Same-Origin Policy para restringir cómo un documento cargado desde un origen puede interactuar con recursos de otro origen. Un origen se define, en términos simples, por combinación de esquema, host y puerto.

Esta política busca reducir el impacto de páginas maliciosas que intentan leer respuestas de otros sitios a los que el navegador del usuario también tiene acceso. CORS aparece como un mecanismo controlado para relajar esa restricción cuando un servidor desea permitir acceso cruzado legítimo.

14.3 Qué es CORS

Cross-Origin Resource Sharing es un conjunto de cabeceras y reglas mediante el cual un servidor declara qué orígenes web pueden leer respuestas o realizar ciertos tipos de solicitudes desde el navegador. En otras palabras, le indica al browser bajo qué condiciones puede compartir recursos con scripts cargados desde otros orígenes.

CORS no es un mecanismo de autenticación ni de autorización del lado servidor. Es una política que el navegador hace cumplir cuando un script web intenta consumir una API cross-origin.

CORS controla qué puede leer un navegador desde otro origen. No controla directamente qué puede hacer un atacante que llama a la API fuera del navegador.

14.4 Qué resuelve CORS y qué no resuelve

CORS ayuda a controlar CORS no resuelve por sí solo
Qué orígenes web pueden leer respuestas desde el browser Autorización real sobre recursos
Qué métodos y cabeceras están permitidos en cross-origin Protección contra clientes no browser
Uso de credenciales en solicitudes web cross-origin CSRF, si no se diseña el flujo adecuadamente
Exposición de respuestas a scripts de otros orígenes Exposición por tokens robados o APIs públicas mal diseñadas

14.5 Cabeceras principales de CORS

Las políticas CORS suelen expresarse con cabeceras específicas. Comprenderlas es clave para no abrir más de lo debido.

  • Access-Control-Allow-Origin: define qué origen puede acceder.
  • Access-Control-Allow-Credentials: indica si el navegador puede incluir credenciales.
  • Access-Control-Allow-Methods: enumera métodos permitidos para cross-origin.
  • Access-Control-Allow-Headers: define qué cabeceras pueden enviarse.
  • Access-Control-Expose-Headers: define qué cabeceras de respuesta pueden leer los scripts.

14.6 El problema de `Access-Control-Allow-Origin: *`

Permitir cualquier origen puede parecer conveniente, pero amplía la superficie de exposición. En APIs realmente públicas y sin credenciales puede ser aceptable en algunos casos, pero en APIs con datos sensibles, sesiones o tokens enviados automáticamente, suele ser una mala decisión.

El riesgo aumenta cuando se combina con:

  • Credenciales del navegador.
  • Cookies de sesión.
  • Endpoints administrativos o con datos sensibles.
  • Cabeceras personalizadas para identidad o contexto.

14.7 Orígenes permitidos: listas explícitas

La práctica más segura suele ser mantener una allowlist explícita de orígenes confiables. Eso obliga a decidir conscientemente qué frontends, dominios o subdominios deben poder consumir la API desde un navegador.

Esto implica cuidar:

  • Ambientes separados, como producción y testing.
  • Subdominios legítimos versus comodines innecesarios.
  • Rotación o retiro de orígenes que ya no se usan.
  • Sincronización entre despliegue del frontend y política CORS.

14.8 Credentials y cross-origin

Cuando una API permite `Access-Control-Allow-Credentials`, autoriza al navegador a enviar cookies, autenticación HTTP u otras credenciales asociadas al contexto del usuario. Esto vuelve mucho más delicada la política CORS, porque ya no se trata solo de exponer una API pública sino de permitir acceso cross-origin con identidad implícita.

En ese escenario, no es correcto usar `*` como origen permitido. La política debe ser estricta y específica.

Si el navegador va a enviar credenciales, el origen que puede leer la respuesta debe estar cuidadosamente controlado.

14.9 Preflight requests

Para ciertas solicitudes cross-origin, el navegador realiza primero una petición `OPTIONS` llamada preflight. Su objetivo es preguntar al servidor si la operación real estará permitida bajo CORS.

Esto ocurre típicamente cuando:

  • Se usan métodos distintos de los más simples.
  • Se envían cabeceras personalizadas.
  • El tipo de contenido no cae en los casos simples admitidos por el browser.

Configurar mal las respuestas preflight puede dejar métodos o cabeceras habilitados sin intención real.

14.10 Métodos y cabeceras permitidos

Una API no debería anunciar más métodos o cabeceras de los que realmente necesita para el cliente web autorizado. Cuanto más amplio el permiso, mayor el margen para uso inesperado o abuso desde un origen comprometido.

Buenas prácticas:

  • Permitir solo métodos necesarios.
  • Permitir solo cabeceras efectivamente usadas por el frontend.
  • Revisar regularmente si esos permisos siguen siendo necesarios.

14.11 Access-Control-Expose-Headers

Por defecto, el navegador no expone todas las cabeceras de respuesta al JavaScript del cliente. Si una API declara `Access-Control-Expose-Headers`, está ampliando qué metadata puede leer el script.

Esto es útil en algunos casos, pero también puede revelar:

  • Identificadores internos.
  • Metadata operativa.
  • Información de paginación o correlación que quizá no sea necesaria.

Conviene exponer solo cabeceras que el cliente realmente necesita para funcionar.

14.12 CORS dinámico y riesgos de reflexión

Algunas implementaciones responden reflejando el origen recibido si parece válido. Esto puede ser correcto si se valida contra una allowlist estricta. Pero si la validación es débil o ingenua, puede terminar permitiendo orígenes no previstos.

Errores típicos:

  • Aceptar coincidencias parciales de dominio.
  • Confiar en strings manipulables o formatos ambiguos.
  • Permitir comodines excesivos en subdominios.
  • Basarse en configuración difícil de auditar o inconsistente entre entornos.

14.13 CORS y APIs públicas

No todas las APIs necesitan CORS estricto. Si una API es verdaderamente pública, sin credenciales ni datos sensibles, permitir acceso amplio desde navegadores puede ser una decisión válida. Pero eso debe responder a una intención explícita de producto, no a una configuración por defecto para “evitar problemas”.

La pregunta correcta es: ¿realmente queremos que cualquier sitio pueda usar esta API desde el browser del usuario?

14.14 CORS no reemplaza CSRF ni autorización

Una confusión habitual es creer que una política CORS restrictiva elimina otros riesgos. No es así. CORS regula qué puede leer el JavaScript del navegador desde otro origen, pero no define por sí solo autorización ni elimina la necesidad de proteger flujos con cookies frente a CSRF cuando corresponda.

Tampoco evita que un cliente no browser llame directamente a la API si tiene red y credenciales suficientes.

14.15 Cabeceras de seguridad relacionadas

Además de CORS, existen otras cabeceras que ayudan a reforzar la interacción segura con clientes web. No todas aplican igual a una API JSON, pero algunas siguen siendo relevantes según el contexto de consumo.

Cabecera Propósito
Content-Type Declarar claramente el tipo de respuesta
Cache-Control Controlar almacenamiento de respuestas sensibles
Strict-Transport-Security Reforzar uso exclusivo de HTTPS
X-Content-Type-Options Evitar interpretaciones de tipo no deseadas en ciertos clientes
Referrer-Policy Limitar exposición de URLs y contexto de navegación

14.16 Exposición controlada a frontends

Una API no debería exponerse igual a todos los tipos de clientes. Cuando hay frontends web concretos, conviene diseñar la exposición específicamente para ellos: orígenes definidos, métodos precisos, cabeceras mínimas, credenciales controladas y políticas distintas según ambiente o aplicación.

También puede ser razonable separar APIs públicas, privadas y administrativas en dominios o rutas distintas para evitar políticas CORS excesivamente complejas o ambiguas.

14.17 Riesgos operativos y de mantenimiento

Las políticas CORS tienden a degradarse con el tiempo si no se gobiernan. Se agregan orígenes temporales, ambientes de staging, dominios viejos o comodines “provisorios” que luego quedan en producción.

Por eso es importante:

  • Inventariar qué orígenes están permitidos.
  • Revisar periódicamente reglas y excepciones.
  • Eliminar entradas obsoletas.
  • Tratar cambios CORS como cambios de seguridad, no solo de frontend.

14.18 Errores frecuentes

  • Configurar `Access-Control-Allow-Origin: *` por conveniencia.
  • Permitir credenciales con políticas de origen demasiado amplias.
  • Reflejar orígenes sin validación estricta.
  • Habilitar métodos o cabeceras que el cliente no necesita.
  • Suponer que CORS protege contra clientes no browser.
  • Creer que CORS reemplaza autorización o protección CSRF.
  • Acumular excepciones y orígenes legacy sin revisión.

14.19 Qué debes recordar de este tema

  • CORS es una política aplicada por navegadores para regular acceso cross-origin desde scripts web.
  • No reemplaza autenticación, autorización ni controles de backend.
  • Permitir orígenes, métodos o cabeceras de más amplía superficie de exposición.
  • El uso de credenciales cross-origin exige políticas especialmente estrictas.
  • La exposición a frontends debe diseñarse como una decisión de seguridad explícita y mantenible.

14.20 Conclusión

CORS y las cabeceras relacionadas son parte esencial de la seguridad de una API cuando intervienen navegadores. No protegen la API por sí solos, pero sí definen qué frontends pueden interactuar con ella de manera controlada y cuánto del servicio queda expuesto al entorno web. Configurarlos bien exige precisión, intención y mantenimiento continuo; configurarlos mal suele abrir más superficie de la que el equipo imagina.

En el próximo tema estudiaremos rate limiting, cuotas, throttling y defensa frente a abuso y denegación de servicio, para analizar cómo controlar el consumo de la API y resistir automatización agresiva.