Compartir Recursos de Origen-Cruzado (CORS)

  • Posted on: 19 October 2022
  • By: ReYDeS

Algunas características de HTML5 reflejan la experiencia real de los desarrolladores web, quienes han estado ampliando los límites de las capacidades del navegador para crear aplicaciones las cuales se vean, sientan, y funcionen igual a las aplicaciones "nativas" instaladas en el sistema del usuario. Uno de esos límites en los cuales se enfatiza es la venerable política del mismo origen, uno de los pocos mecanismos de seguridad presentes en los primeros navegadores. Los desarrolladores frecuentemente tienen razones legítimas para relajar la Política de Mismo Origen, ya sea para permitir un sitio se extienda a través de nombres de dominio específicos, o para hacer posible una interacción útil de sitios sobre dominios no relacionados. CORS permite a los desarrolladores de sitios otorgar permiso para un origen pueda acceder al contenido de los recursos cargados desde un origen diferente. (El comportamiento predeterminado del navegador permite solicitar recursos de diferentes orígenes, pero el acceso al contenido de cada recurso de respuesta está aislado por origen. Un sitio no puede asomarse al DOM de otro, por ejemplo, establecer cookies, leer nodos de texto conteniendo nombres de usuario, inyectar nodos JavaScript, etc.)

Uno de los caballos de batalla del navegador para producir peticiones es el objeto XMLHttpRequest (XHR). Dos de sus principales características, la capacidad de realizar peticiones asíncronas en segundo plano, y la capacidad de utilizar métodos no GET, lo convierten en un componente clave para los exploits. Como consecuencia, los navegadores han limitado cada vez más las capacidades de XHR para reducir su exposición adversa a la seguridad. Con CORS, los desarrolladores web pueden ampliar esos límites sin poner indebidamente en riesgo a los navegadores.

Los límites de seguridad en los recursos de origen cruzado se establecen mediante cabeceras de petición y respuesta. El navegador tiene tres cabeceras de petición:

Origin: El esquema/host/puerto del recurso iniciando la petición. El compartir debe ser otorgado para este Origen por el servidor. La seguridad asociada a esta cabecera se basa en provenir desde un navegador no comprometido. Su valor debe ser establecido con precisión por el navegador; no debe ser modificado por HTML, JavaScript o plugins.

Access-Control-Request-Method: Se utiliza en una petición de verificación previa para determinar si el servidor respetará el método o métodos requeridos de utilizar por el objeto XHR. Por ejemplo, es posible un navegador sólo necesite confiar en GET para una aplicación web, pero requiera un rango de métodos para un sitio web REST-ful. Por lo tanto, un sitio web puede imponer al navegador un concepto de "mínimos privilegios", por el cual sólo honra aquellos métodos considerados necesarios.

Access-Control-Request-Headers: Se utiliza en una petición de verificación previa para determinar si el servidor honrará las cabeceras adicionales requeridos de establecer por el objeto XHR. Por ejemplo, JavaScript para el lado del cliente tiene prohibido manipular la cabecera Origin. Por otro lado, el objeto XHR puede requerir subir archivos a través de un método POST, en cuyo caso puede ser deseable establecer una cabecera Content-Type (aunque los navegadores limitarán los valores pudiendo contener esta cabecera).

El servidor tiene cinco cabeceras de respuesta instruyendo al navegador sobre aquello lo cual debe permitir en términos de compartir el acceso hacia los datos de una respuesta hacia una petición de origen cruzado:

Access-Control-Allow-Credentials Puede ser "true" (verdadero) o "false" (falso). Por defecto el navegador no enviará cookies, cadenas de autenticación HTTP (por ejemplo, Basic, Digest, NTLM), o certificados SSL de cliente a través de los orígenes. Esta restricción evita el contenido malicioso intente filtrar las credenciales hacia un origen no aprobado. Si se establece este encabezado como verdadero, cualquier dato de esta categoría de credenciales se puede compartir entre orígenes.

Access-Control-Allow-Headers Las cabeceras pueden incluir una petición. Existen cabeceras inmutables, como Host y Origin. Esto se aplica a cabeceras como
Content-Type, así como a las X-headers personalizadas

Access-Control-Allow-Methods Los métodos factible de ser utilizados por una solicitud para obtener el recurso. Siempre es preferible limitar los métodos a los cuales se consideren necesarios, lo cual es usualmente sólo GET.

Access-Control-Allow-Origin El origen u orígenes con los cuales el servidor permite al navegador compartir los datos de respuesta del servidor. Puede ser un origen explícito (por ejemplo, http: //otro.site), * (por ejemplo un comodín para coincidir con cualquier origen, o "null" (para negar solicitudes). El comodín ( * ) siempre impide las credenciales se incluyan en una solicitud de origen cruzado, independientemente de la cabecera Access-Control-Allow-Credentials.

Access-Control-Expose-Headers Una lista de cabeceras factible de hacer visibles por el navegador para el cliente. Por ejemplo JavaScript podría leer las cabeceras expuestas de una respuesta XHR.

Access-Control-Max-Age La duración en segundos durante el cual se puede almacenar en caché la respuesta para una solicitud de verificación previa. Los tiempos más cortos incurren en una mayor sobrecarga, pues el navegador se ve forzado a renovar sus permisos CORS con una nueva petición de verificación previa. Los tiempos más largos aumentan la exposición potencial de los controles excesivamente permisivos desde una solicitud de verificación previa. Esta es una decisión política para los desarrolladores web. Una buena referencia para este valor sería la cantidad de tiempo una aplicación web mantiene la sesión de un usuario sin requerir la reautenticación, como un botón "Recuérdame" común entre los sitios. Así las duraciones típicas pueden ser de unos minutos, un día laborable o dos semanas, con preferencia por tiempos más cortos.

Compartir recursos entre orígenes debe ser permitida por el sitio web. El acceso a los datos de respuesta ante peticiones GET y POST usuales, estará siempre restringido al mismo origen, a menos la respuesta contenga una de las cabeceras relacionadas con CORS. Un servidor puede responder a estos tipos de peticiones "usuales" con cabeceras para control de acceso. En otras situaciones el navegador puede utilizar primero una petición previa para establecer una política CORS. Esto es más común cuando se utiliza el objeto XHR.

En este ejemplo, suponer el HTML se carga desde un Origen de http: //web.site. El siguiente JavaScript muestra una petición XHR realizado con un método PUT hacia otro Origen (http ://friendly.app) el cual requiere incluir credenciales (el valor "true" para el tercer argumento de la función xhr.open()):

var xhr = new XMLHttpRequest();
xhr.open("PUT", "http: //friendly.app/other_origin.html", true);
xhr.send();

Una vez se procesa xhr.send(), el navegador inicia una petición de verificación previa para determinar si el servidor está dispuesto a compartir un recurso de su propio origen http: //friendly.app con el origen http: //web.site del recurso solicitante. La petición se parece a lo siguiente

OPTIONS http ://friendly.app/other_origin.html HTTP/1.1
Host: friendly.app
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:11.0) Gecko/20100101 Firefox/11.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Origin: http: //web.site
Access-Control-Request-Method: PUT

Si el servidor de friendly.app desea compartir recursos con http: //web.site, entonces responderá con algo como:

HTTP/1.1 200 OK
Date: Tue, 03 Apr 2022 06:51:53 GMT
Server: Apache
Access-Control-Allow-Origin: http: //web.site
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 10
Content-Length: 0

Este intercambio de cabeceras indica al navegador exponga el contenido de las respuestas del origen http: //friendly.app con los recursos cargados desde el origen http: //web.site. Así un objeto XHR podría recibir datos JSON de friendly.app factibles de ser leídos, manipulados y mostrados por web.site.

CORS es un acuerdo entre orígenes el cual instruye al navegador relajar la Política de Mismo Origen, lo cual de otra manera impediría los datos de respuesta de un origen estuviesen disponibles para los recursos del lado del cliente de otro origen. Permitir CORS acarrea implicaciones de seguridad para una aplicación web. Por lo tanto, es importante tener en consideración los principios sobre la Política de Mismo Origen cuando se relaja intencionalmente:

  • Asegúrese de el código del servidor siempre verifica las cabeceras Origin y Host coinciden, y el Origen coincide con una lista de valores permitidos antes de responder con cabeceras CORS. Seguir el principio de "fallo seguro": cualquier error debería devolver una respuesta vacía o una respuesta con el mínimo contenido.
  • Recordar CORS establece el compartir por origen, no por recurso. Si sólo es necesario compartir un único recurso, considerar la posibilidad de mover ese recurso hacia su propio subdominio en lugar de exponer el resto de los recursos de la aplicación web. Por ejemplo, establecer un origen separado para el acceso hacia la API en lugar de exponer la API a través de un directorio en el origen principal del sitio.
  • Utilizar un valor comodín ( * ) para el encabezado Access-Control-Allow-Origin con moderación. Este valor expone los datos del recurso (por ejemplo la página web) hacia las páginas de cualquier sitio web. Recordar la política de mismo origen no impide una página cargue recursos desde orígenes no relacionados, sino previene la página lea los datos de respuesta de esos orígenes.
  • Evalúe el impacto añadido para los ataques de inyección HTML (cross-site scripting). Una inyección de HTML exitosa será capaz de ejecutarse dentro del origen del sitio víctima. Cualquier relación de confianza establecida con CORS estará adicionalmente expuesta al exploit.

CORS es una de las características de HTML5 el cual tiene uso como utilidad para los exploits web. Esto no significa CORS sea fundamentalmente defectuoso o inseguro. Significa los ciberatacantes seguirán exfiltrando datos del navegador, escaneando redes en busca de hosts vivos o puertos abiertos, e inyectando JavaScript utilizando nuevas tecnologías. Las aplicaciones web no serán menos seguras, los exploits serán más sofisticados.

Fuentes:

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
https://en.wikipedia.org/wiki/Cross-origin_resource_sharing

Sobre el Autor


Alonso Eduardo Caballero Quezada - ReYDeS
Instructor y Consultor Independiente en Ciberseguridad
WhatsApp: https://wa.me/51949304030
Correo Electrónico: ReYDeS@gmail.com
Twitter: https://twitter.com/Alonso_ReYDeS
Youtube: https://www.youtube.com/c/AlonsoCaballero
LinkedIn: https://pe.linkedin.com/in/alonsocaballeroquezada/