Ways to circumvent the same-origin policy
Asked Answered
C

8

150

The same origin policy

I wanted to make a community wiki regarding HTML/JS same-origin policies to hopefully help anyone searching for this topic. This is one of the most searched-for topics on SO and there is no consolidated wiki for it so here I go :)

The same origin policy prevents a document or script loaded from one origin from getting or setting properties of a document from another origin. This policy dates all the way back to Netscape Navigator 2.0.

What are some of your favorite ways to go around same-origin policies?

Please keep examples verbose and preferably also link your sources.

Crapulent answered 19/6, 2010 at 17:1 Comment(3)
nice idea.. You should put your examples into answer(s) though; as it stands, they make the question rather bulkyDarrow
You should also add a list of security implications for each approach. JSONP is highly insecure for private data.Deliciadelicious
Why the close? This (wiki) question has been quite useful for the past 2 years. Furthermore, many answers are supported by references. An explanation would be appreciated as a not constructive tag seems utterly inane. Voted for re-open.Crapulent
C
84

The document.domain method

  • Method type: iframe.

Note that this is an iframe method that sets the value of document.domain to a suffix of the current domain. If it does so, the shorter domain is used for subsequent origin checks. For example, assume a script in the document at http://store.company.com/dir/other.html executes the following statement:

document.domain = "company.com";

After that statement executes, the page would pass the origin check with http://company.com/dir/page.html. However, by the same reasoning, company.com could not set document.domain to othercompany.com.

With this method, you would be allowed to exectue javascript from an iframe sourced on a subdomain on a page sourced on the main domain. This method is not suited for cross-domain resources as browsers like Firefox will not allow you to change the document.domain to a completely alien domain.

Source: https://developer.mozilla.org/en/Same_origin_policy_for_JavaScript

The Cross-Origin Resource Sharing method

  • Method type: AJAX.

Cross-Origin Resource Sharing (CORS) is a W3C Working Draft that defines how the browser and server must communicate when accessing sources across origins. The basic idea behind CORS is to use custom HTTP headers to allow both the browser and the server to know enough about each other to determine if the request or response should succeed or fail.

For a simple request, one that uses either GET or POST with no custom headers and whose body is text/plain, the request is sent with an extra header called Origin. The Origin header contains the origin (protocol, domain name, and port) of the requesting page so that the server can easily determine whether or not it should serve a response. An example Origin header might look like this:

Origin: http://www.stackoverflow.com

If the server decides that the request should be allowed, it sends a Access-Control-Allow-Origin header echoing back the same origin that was sent or * if it’s a public resource. For example:

Access-Control-Allow-Origin: http://www.stackoverflow.com

If this header is missing, or the origins don’t match, then the browser disallows the request. If all is well, then the browser processes the request. Note that neither the requests nor responses include cookie information.

The Mozilla team suggests in their post about CORS that you should check for the existence of the withCredentials property to determine if the browser supports CORS via XHR. You can then couple with the existence of the XDomainRequest object to cover all browsers:

function createCORSRequest(method, url){
    var xhr = new XMLHttpRequest();
    if ("withCredentials" in xhr){
        xhr.open(method, url, true);
    } else if (typeof XDomainRequest != "undefined"){
        xhr = new XDomainRequest();
        xhr.open(method, url);
    } else {
        xhr = null;
    }
    return xhr;
}

var request = createCORSRequest("get", "http://www.stackoverflow.com/");
if (request){
    request.onload = function() {
        // ...
    };
    request.onreadystatechange = handler;
    request.send();
}

Note that for the CORS method to work, you need to have access to any type of server header mechanic and can't simply access any third-party resource.

Source: http://www.nczonline.net/blog/2010/05/25/cross-domain-ajax-with-cross-origin-resource-sharing/

The window.postMessage method

  • Method type: iframe.

window.postMessage, when called, causes a MessageEvent to be dispatched at the target window when any pending script that must be executed completes (e.g. remaining event handlers if window.postMessage is called from an event handler, previously-set pending timeouts, etc.). The MessageEvent has the type message, a data property which is set to the string value of the first argument provided to window.postMessage, an origin property corresponding to the origin of the main document in the window calling window.postMessage at the time window.postMessage was called, and a source property which is the window from which window.postMessage is called.

To use window.postMessage, an event listener must be attached:

    // Internet Explorer
    window.attachEvent('onmessage',receiveMessage);

    // Opera/Mozilla/Webkit
    window.addEventListener("message", receiveMessage, false);

And a receiveMessage function must be declared:

function receiveMessage(event)
{
    // do something with event.data;
}

The off-site iframe must also send events properly via postMessage:

<script>window.parent.postMessage('foo','*')</script>

Any window may access this method on any other window, at any time, regardless of the location of the document in the window, to send it a message. Consequently, any event listener used to receive messages must first check the identity of the sender of the message, using the origin and possibly source properties. This cannot be understated: Failure to check the origin and possibly source properties enables cross-site scripting attacks.

Source: https://developer.mozilla.org/en/DOM/window.postMessage

Crapulent answered 19/6, 2010 at 17:1 Comment(4)
stackoverflow.com/questions/7680776/…Rhigolene
I hope im not too late to get an answer: by only question is, is localhost ALWAYS an exception? is it always not allowed? should I stop testing through my localhost?Withhold
I am not sure why but when I set: Access-Control-Allow-Origin: http://www.stackoverflow.com/ instead of: Access-Control-Allow-Origin: http://www.stackoverflow.com (slash on the end of url), it does not work in Safari and FF but works in Chrome. Of course without slash works fine in all browsers.Phidias
Might be worth letting people know that the postMessage method only works for browsers that support it, as it is an HTML5 addition. This plugin tries to account for that. Just mentioning it because I'm learning this the hard way.Revitalize
H
41

The Reverse Proxy method

  • Method type: Ajax

Setting up a simple reverse proxy on the server, will allow the browser to use relative paths for the Ajax requests, while the server would be acting as a proxy to any remote location.

If using mod_proxy in Apache, the fundamental configuration directive to set up a reverse proxy is the ProxyPass. It is typically used as follows:

ProxyPass     /ajax/     http://other-domain.com/ajax/

In this case, the browser would be able to request /ajax/web_service.xml as a relative URL, but the server would serve this by acting as a proxy to http://other-domain.com/ajax/web_service.xml.

One interesting feature of the this method is that the reverse proxy can easily distribute requests towards multiple back-ends, thus acting as a load balancer.

Hangout answered 19/6, 2010 at 17:1 Comment(0)
M
17

I use JSONP.

Basically, you add

<script src="http://..../someData.js?callback=some_func"/>

on your page.

some_func() should get called so that you are notified that the data is in.

Millar answered 19/6, 2010 at 17:1 Comment(5)
JSONP has two problems: a) You are adding a script tag to the target domain. They can send anything back, even regular javascript (XSS attack). So you really have to trust them not to do bad stuff or become hacked b) Any other webpage can add the same script-tag, and steal the data, so never ever use JSONP for private data.Deliciadelicious
@Erlend: Any information served on the web can be retrieved by anyone (unless proper authentication is required). The exact format of how that information is presented does not make this better or worse, not even if it's JSONP.Intercolumniation
@T-Bull: The problem is that proper authentication is impossible with JSONP. A user logs in on site A and then goes to site B, which loads data from A using a JSONP script tag. As is well and good. Then the user is tricked into visiting evil site C, which also uses a JSONP script tag to load data from A. So because the user is authenticated with A, the owner of C can now steal the users data from A. And that's even if the user used two factor authentication to authenticated with A. The problem is that JSONP is highly insecure. And JSONP is not presentation. It's insecure data transfer.Deliciadelicious
JSONP only supports HTTP GET.Meagher
What .js file does this represent -> "http://..../someData.js....I'm trying to read the dom from another site client-side, and need to circumvent the same-origin policy.Pollie
R
13

AnyOrigin didn't function well with some https sites, so I just wrote an open source alternative called whateverorigin.org that seems to work well with https.

Code on github.

Rhigolene answered 19/6, 2010 at 17:1 Comment(2)
@DavidTitarenco - it drove me crazy trying to understand some of the things going on in the belly of anyorigin. Luckily I found one blog post that helped, and now the next guy will have a working test site if he ever needs it.Rhigolene
@neoascetic - fixed the usage ... the URL needs to be encoded now.Rhigolene
L
12

The most recent way of overcoming the same-origin policy that I've found is http://anyorigin.com/

The site's made so that you just give it any url and it generates javascript/jquery code for you that lets you get the html/data, regardless of it's origin. In other words, it makes any url or webpage a JSONP request.

I've found it pretty useful :)

Here's some example javascript code from anyorigin:

$.getJSON('http://anyorigin.com/get?url=google.com&callback=?', function(data){
    $('#output').html(data.contents);
});
Lathan answered 19/6, 2010 at 17:1 Comment(3)
Although it gave me some issues with https sites, so check out my open source alternative below: stackoverflow.com/questions/3076414/…Rhigolene
Which means that: a) anyorigin will be able to read all your data transferred through tem b) anyorigin can XSS your site, read all your data on your site, and deliver malware to your users (what happens if anyorigin is hacked?)Deliciadelicious
@Deliciadelicious - fork Whateverorigin and host it on your own server. The code is trivial so you can review it to make sure no exploits are hidden there.Rhigolene
C
3

The JSONP comes to mind:

JSONP or "JSON with padding" is a complement to the base JSON data format, a usage pattern that allows a page to request and more meaningfully use JSON from a server other than the primary server. JSONP is an alternative to a more recent method called Cross-Origin Resource Sharing.

Cockle answered 19/6, 2010 at 17:1 Comment(1)
See my comment to JSONP above. Not a good choice for private data.Deliciadelicious
D
1

Well, I used curl in PHP to circumvent this. I have a webservice running in port 82.

<?php

$curl = curl_init();
$timeout = 30;
$ret = "";
$url="http://localhost:82/put_val?val=".$_GET["val"];
curl_setopt ($curl, CURLOPT_URL, $url);
curl_setopt ($curl, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt ($curl, CURLOPT_MAXREDIRS, 20);
curl_setopt ($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5");
curl_setopt ($curl, CURLOPT_CONNECTTIMEOUT, $timeout);
$text = curl_exec($curl);
echo $text;

?>

Here is the javascript that makes the call to the PHP file

function getdata(obj1, obj2) {

    var xmlhttp;

    if (window.XMLHttpRequest)
            xmlhttp=new XMLHttpRequest();
    else
            xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");

    xmlhttp.onreadystatechange=function()
    {
        if (xmlhttp.readyState==4 && xmlhttp.status==200)
        {
                document.getElementById("txtHint").innerHTML=xmlhttp.responseText;
        }
    }
    xmlhttp.open("GET","phpURLFile.php?eqp="+obj1+"&val="+obj2,true);
    xmlhttp.send();
}

My HTML runs on WAMP in port 80. So there we go, same origin policy has been circumvented :-)

Domineer answered 19/6, 2010 at 17:1 Comment(0)
U
1

Personally, window.postMessage is the most reliable way that I've found for modern browsers. You do have to do a slight bit more work to make sure you're not leaving yourself open to XSS attacks, but it's a reasonable tradeoff.

There are also several plugins for the popular Javascript toolkits out there that wrap window.postMessage that provide similar functionality to older browsers using the other methods discussed above.

Unquestionable answered 19/6, 2010 at 17:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.