Ways to Circumvent the Same-Origin Policy

Ways to circumvent the same-origin policy

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

How to circumvent same-origin policy for a 3rd party https site?

Sorry, it seems that anyorigin.com does support https.

The reason I naively thought it doesn't, is because the API in question returns JSON, and I thought I would actually just get a plain text response (as in my tests with using anyorigin.com on google.com). When it returned just an object, I figured something was broken.

It appears the object simply returns the parsed JSON, so I'm good to go!

Update - anyorigin.com stopped working with some https sites a few weeks after I posted this, so I went ahead and wrote whateverorigin.org, an open source alternative to anyorigin.

Userscript to bypass same-origin policy for accessing nested iframes

I think the only way you can do it, is by using the window.postMessage() method to send messages with data from iframes to the top window. To catch each iframe inside Greasemonkey script see Brock Adams answer on Apply a Greasemonkey userscript to an iframe?; you'll have to use the GM @match directive like this:

// @match        http://subdomain1.example.com/*

or

// @match        *.example.com/*

Then you can check if the current window is the top window, and/or check the document.domain to identify the iframe:

// ==UserScript==
// @name New Userscript
// @match http://main-domain.something
// @match *.example.com/*
// ==/UserScript==

(function() {
'use strict';

if (window.top === window.self) {
// Here we are at the top window and we setup our message event listener
}
else {
// Here we get inside the iframes.
// We can address and check each iframe url with document.domain
}
})();

We need to hook an event for "message" to the top window that will handle each message it receives from the iframes with the data:

window.addEventListener("message", function(event) {
// do something with the event.data
}, false);

And we can identify the iframes by using document.domain; do whatever manipulation we need to the iframe elements; retrieve all the data we want and send the message to the top window:

window.top.postMessage({
// data object we send to the top window
}, "*");

I created a demo to try this and it works pretty well. My top window URL is http://zikro.gr/dbg/gm/iframes/main.php and the subdomains are like http://subdomain1.zikro.gr/. The top window HTML is identical to yours with my iframe urls and the GM script:

// ==UserScript==
// @name New Userscript
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author You
// @match http://zikro.gr/dbg/gm/iframes/main.php
// @match *.zikro.gr/*
// @grant none
// ==/UserScript==

(function() {
'use strict';

if (window.top === window.self) {
// Here we are at the top window and we setup our message event listener
document.body.style.backgroundColor = "#f00"; // Just a UI change to identify the top window
window.addEventListener("message", function(event) {
window.console.log("This is data from '" + event.data.title +
"'; with message '" + event.data.message +
"'; with data '" + event.data.data +"'" +
"'; from domain '" + event.data.domain + "'");
}, false);
}
else {
// Here we get inside the iframes.
// We can address and check each iframe url with document.domain

document.body.style.backgroundColor = "#0f0"; // Just a UI change to identify the iframe window

// We change something inside the iframe
var dataDiv = document.getElementsByTagName('div')[0];
dataDiv.innerHTML += " with a change!";

// And we post a message to the top window with all the data we want inside an object
window.top.postMessage({
title: document.title,
domain: document.domain,
message: "Hello from, iframe - " + document.title,
data: dataDiv.innerText
}, "*");
}

})();

And a screen capture for those who don't have Greasemonkey/Tampermoney installed to test this:

Script in action

PS: It's not valid to add elements directly inside an iframe tag like this:

<iframe id="outer_iframe_2" src="https://subdomain2.example.com">
<div>
<iframe id="inner_iframe_2" src="https://subdomain4.example.com"></iframe>
</div>
</iframe>

Anyway to bypass same origin policy?

No, there is not. It would not be much of a security measure if it could be circumvented. If you want to access Twitter data, use their API.

Actually, there is a workaround that is possible: since same origin policy only affects clients, you can ask your server to fetch it for you. However, most sites that provide API frown on unauthenticated scraping, and might blacklist your site. Specifically, by Twitter ToS:

however, scraping the Services without the prior consent of Twitter is expressly prohibited

EDIT: The link by Skizo is excellent. But while it lists many ways to deal with the policy, none except serverside proxying will help you circumvent the policy on a non-cooperating third-party site.

How to bypass Cross origin policy

As already answered, you want a simple php proxy script.

This way your server grabs the json file and you simply access your server from client side. . That way javascript is only dealing with the same domain.

<?php
header('Content-Type: application/json');
echo file_get_contents('http://example.com/data.json');
?>

Proxy.php

<?php
header('Content-Type: application/json');
echo file_get_contents('http://example.com/'.$_REQUEST['file']);
?>

Another way also would be to send all of the request headers as a query string, this could be post/get as well


if (isset($_REQUEST['query'])) {
$sQuery = http_build_query($_REQUEST);
header('Content-Type: application/json');
echo file_get_contents('https://www.example.com?'.$sQuery);
exit;
}

?>

Using the second example you can try something like http://localhost/proxy.php?file=somefile.json

HTACCESS METHOD

Refer the following page about using a htaccess file on the server htaccess Access-Control-Allow-Origin

<FilesMatch ".(json|js|jsn)">
Header set Access-Control-Allow-Origin "*"
</FilesMatch>


Related Topics



Leave a reply



Submit