Product SiteDocumentation Site

3.2.2. Bypassing same origin policy

Same Origin Policy as security mechanism leaves a lot to be desired: on one hand, it is not flexible enough to allow web developers use cross-domain resources in several legitimate usecases without exceptions to the rule and workarounds, on the other hand, such exceptions create opportunities for attacker.
There are several other mechanisms except document.domain that provide a way to relax Same Origin Policy.

3.2.2.1. Cross-origin resource sharing (CORS)

Cross-origin resource sharing is a mechanism that allows web application to inform browser, whether cross domain requests against the requested resource are expected.
Web browsers that conform to the CORS alter their behaviour of handling XMLHttpRequests: instead of denying the cross-domain request immediately, HTTP request is sent with Origin header. Let's assume http://example.com/testpage is making a XMLHttpRequest against http://content.com/wanted_image. Request would contain:
GET /wanted_image HTTP/1.1
Referrer: http://example.com/testpage
Origin: http://example.com
If the server allows sharing of the resource with domain that originated the request, the response would include:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://example.com
..
By sending Access-Control-Allow-Origin header, server explicitly tells browser that this cross domain request shall be allowed. Allowed values of Access-Control-Allow-Origin are: * (denoting any domain, effectively marking the resource public) or space separated list of allowed origins (in practice, this usually contains just a single domain - one that was specified in Origin header in request).
If the resource should not be accessible by the originating domain, server ought not include Access-Control-Allow-Origin header in the response. By default, upon receiving such response from server browser will not pass the response back to the page that originated the request.
Several additional considerations:
  • If the browser is outdated and does not conform to CORS, cross domain request will be denied immediately without sending the request to the server. This means usability of web applications relying on CORS might be restricted on old browsers.
  • If the web server does not conform to CORS, the Access-Control-Allow-Origin header will not be included in the response and the request will be denied on the client side.
  • Cross-domain access to resources is enforced on the side of the client. However, since the request includes Origin header, server may also restrict access to resources from other domains (e.g. by returning nothing).
  • If the origin of page is unknown (for example webpage is running from a file), browsers will send
    Origin: null
    
3.2.2.1.1. Using CORS in Rack-based applications
CORS support for Rack-based applications is provided by rack-cors gem. After adding it to the applications Gemfile
gem 'rack-cors', :require => 'rack/cors'
and configure Rails by modifying config/application.rb:
module YourApp
class Application < Rails::Application

  # ...

  config.middleware.use Rack::Cors do
    allow do
      origins '*'
      resource '*', :headers => :any, :methods => [:get, :post, :options]
    end
  end

end
end
This configuration permits all origins access to any resource on the server via GET, POST and OPTIONS methods. Customizing the configuration, developer of the application can restrict cross-domain acess to resources by origin, headers and methods.

3.2.2.2. JSON with padding (JSONP)

JSONP is a very common way of hacking around the Same Origin Policy. This mechanism makes use of <script> tag and the fact that embedding Javascript code from other domains is not resctricted by the same origin policy. Since the code references by src attribute of <script> tag is loaded, it can be used as a vehicle to carry data and return them after evaluation.
Lets assume webpage needs to access resource at http://example.com/resource/1, which returns JSON data like:
{"Key1": "Value1", "Key2": "Value2"}
When webpage requests the resource with
<source src="http://example.com/resource/1"></source>
after receiving the response, browser will try to evaluate received data. Since data are not executable, interpreter would end with error and data would not be accessible to the code that requested it.
To work around this, it would be enough if the returned data were enclosed with function, that would be able to parse them on the client side. Suppose function parseData can accept JSON data as argument, parse it and make it accessible to the rest of the page:
parseData({"Key1": "Value1", "Key2": "Value2"})
However, web server does not know the name of the function that will parse data. Final piece is to pass the name of data-parsing function to server as parameter in request:
<script src="http://example.com/resource/1?jsonp=parseData"></script>
This technique of sharing resources across domains carries bigger security risks than CORS. Since source tag does not fall under Same Origin Policy on the client side, browser sends normal HTTP GET request without Origin header. Server that receives request has no means to know that the request was generated on behalf of page from other domain. Since neither the browser nor the server checks this kind of cross-domain requests, last obstacle that prevents exploitation is the fact that returned response is evaluated as Javascript code.
Example of this type of vulnerability is CVE-2013-6443. Cloud Forms Manage IQ application has been found vulnerable to cross-domain requests issued using JSONP. UI of application makes heavy use of Javascript and in this particular case changing the tab to "Authentication" would generate this HTTP request through XMLHttpRequest API:
GET /ops/change_tab/?tab_id=settings_authentication&callback=...
Referrer: ...
Cookie: ...
Response returned by the server would look like this:
HTTP/1.1 200 OK
....


miqButtons('hide');
Element.replace("ops_tabs", "<div id=\"ops_tabs\" ...");
where ops_tabs div contained html code of the Authentication tab including form with hidden CSRF token. To exploit this vulnerability, attacker would patch Element.replace function on his page and issue a JSONP request against CFME server.
<script src='http://code.jquery.com/jquery-1.10.2.min.js'></script>
<script>
function test() {
$.ajax({
    url: $( "input[name=url]" ).val() + '/ops/change_tab/?tab_id=settings_authentication',
    dataType: 'jsonp'
});
};

var Element = { replace: function (a,text) { 
...
}
>/script>
This way attacker can run arbitrary code on returned response from the server: since the request also contains CSRF token, it is easy for attacker to steal it and issue successful CSRF request on behalf of currently logged-in user.

3.2.2.3. References: