QNimate

  • CoursesVideos
  • WP PremiumPlugins
  • DemosLab
  • Home
  • QIdea
  • QTrack
Home Carbon Ads Bypass Same Origin Policy

Bypass Same Origin Policy

same-origin-policy

Same origin policy is a set of restrictions that are applied to webpages from communicating with each other. These restrictions prevent a lot of hacks.There are many ways to bypass this restrictions also.

In this post we will look at Same origin policy for different components of web browsing. We will also see the different ways in which we can bypass this restrictions.

Same Origin policy is applied to these functionalities of a webpage

same origin-policy

Same Origin policy can be bypassed by the following ways
same origin policy

Now we will look at each of these functionalities in nutshell.


Two webpages are said to have same origin if they have same protocol, domain name and port number.


Same origin policy for accessing DOM

A webpage inside an iframe/frame is not allowed to modify or access the DOM of its parent or top page and vice-versa if both pages don’t belong to same origin.

There are three ways of bypassing this restriction

  • window.document.domain variable manipulation
  • Proxy
  • Cross Document Messaging

A frame or child page can bypass this restriction by setting window.document.domain variable to the same domain name as the parent’s domain name.

Note that window.document.domain value can only be changed to parent’s domain name if the child page’s original domain is a sub domain of parent’s page or parent’s domain name is a sub domain of child’s domain name. For example parent page has domain name “www.example.com” and child page has domain name “www.blog.example.com” then child page can change its domain name to “www.example.com” but not “www.myexample.com”.

Let’s see an example of this
http://www.qnimate.com/parent.html

<iframe src="http://www.blog.qnimate.com/child.html" id="myIFrame"></iframe>
<script>
window.document.domain = "www.qnimate.com";//you also need to set the parent's document.domain variable
window.document.getElementById("myIFrame").contentWindow.document.body.style.backgroundColor = "red";//this access is allowed by default
</script>

http://www.blog.qnimate.com/child.html

<script>
window.document.domain = "www.qnimate.com"; //if we remove this line then the below line will not work and throw a same origin policy exception.
window.parent.document.body.style.backgroundColor = "blue";
</script>

You can also create a proxy script which will serve the content of iFrame from different domain.

Let’s see an example of this
http://www.qnimate.com/parent.html

<iframe src="http://www.qnimate.com/child.php" id="myIFrame"></iframe>
<script>
window.document.getElementById("myIFrame").contentWindow.document.body.style.backgroundColor = "red";//this access is allowed by default
</script>

http://www.qnimate.com/child.php

<?php
    echo file_get_contents('http://www.blog.qnimate.com/child.html');
?>

http:://www.blog.qnimate.com/child.html

<script>
window.document.domain = "www.qnimate.com"; //if we remove this line then the below line will not work and throw a same origin policy exception.
window.parent.document.body.style.backgroundColor = "blue";
</script>

Parent and Child page can also access each other’s DOM by sending messages to each other using Cross Document Messaging API.

Let’s see an example of this
http://www.qnimate.com/parent.html

<iframe src="http://www.blog.qnimate.com/child.html" id="myIFrame"></iframe>
<script>
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";

// Listen to message from child window
eventer(messageEvent,function(e) {
    if(e.data == "changebgofparent")
    {
        document.body.style.backgroundColor = "blue";
    }
},false);

window.document.getElementById("myIFrame").contentWindow.postMessage("changebgofchild","*");
/*postMessage second parameter represents the domain name to which this message can be sent to, if the child domain name doesn't match then this message will not be sent. Here * means any domain */
</script>

http://www.blog.qnimate.com/child.html

<script>
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";

// Listen to message from child window
eventer(messageEvent,function(e) {
    if(e.data == "changebgofchild")
    {
        document.body.style.backgroundColor = "red";
    }
},false);

window.parent.postMessage("changebgofparent","*");
/*postMessage second parameter represents the domain name to which this message can be sent to, if the child domain name doesn't match then this message will not be sent. Here * means any domain */
</script>


Same Origin Policy for AJAX

A webpage cannot make a AJAX Request to an another page if they both don’t belong to the same origin policy.

There are basically three ways of bypassing this restriction

  • Proxy server
  • JSONP
  • Cross-Origin Resource Sharing

To bypass this policy we can use a proxy script to get the contents of a remote file that doesn’t belong to the same origin.

Let’s see an example of this

http://www.qnimate.com/index.html

<script>
function loadXMLDoc()
{
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("myDiv").innerHTML=xmlhttp.responseText;
    }
}
xmlhttp.open("GET","http://www.qnimate.com/ajaxdata.php",true);
xmlhttp.send();
}
</script>
</head>
<body>

<button type="button" onclick="loadXMLDoc()">Request data</button>
<div id="myDiv"></div>

http://www.qnimate.com/ajaxdata.php

<?php
   echo file_get_contents('http://www.qscutter.com/ajaxdata.txt');
?>

Although a XMLHTTPRequest object cannot make a cross origin request, but a <script> tag can retrieve a JSON from a cross domain url. We can take advantage of this feature and make a request to cross origin url. This way of bypassing cross origin policy is called JSONP.

The name itself indicates that we load JSON data dynamically using <script> tags and make use of that data using JavaScript. But loading JSON directly using <script> tags will raise a error because it cannot be accessed until its assigned to a variable. So we can wrap the JSON data around a function call. So the “P” in JSONP indicated padding JSON around a function call.

Let’s see an example of this
http://www.qnimate.com/index.html

<body id="myBody">
<script type="text/javascript">
function dynamicLoad()
{
    var script= document.createElement('script');
    script.type= 'text/javascript';
    script.src= 'http://www.qscutter.com/ajaxdata.js';
    document.getElementById("myBody").appendChild(script);
}

function parseJSON(JSONdata)
{
   alert(JSONdata.name);
}
dynamicLoad();
</script>

http://www.qscutter.com/ajaxdata.js

parseJSON({"Name": "Narayan Prusty", "Profession": "Programmer"})

The recommended way of bypassing cross origin policy for AJAX is using Cross-Origin Resource Sharing. CORS is a W3C HTTP specification that allows cross-domain communication using AJAX Object. CORS comes in two varieties: simple CORS and complex CORS.

Simple CORS can be used in case you want to make a GET or POST request along with common headers(Accept, Accept-Language, Content-Language, Last-Event-ID and Content-Type with these values only application/x-www-form-urlencoded, multipart/form-data, text/plain). If you want to make any other kind of request then you have to use Complex CROS.

cross origin resource sharing

Let’s see an example of Simple CORS

http://www.qnimate.com/index.html

<script type="text/javascript">

var CROSObject = null;
if(typeof(XMLHttpRequest) != "undefined")
{
    //XMLHttpRequest2 is required for CORS Request
    CROSObject = new XMLHttpRequest();
    //setting this variable to true allows sending and receiving of cokkies.
    CROSObject.withCredentials = true;
}
else if(typeof(XDomainRequest) != "undefined")
{
    //For IE XDomainRequest is required for CORS request
    CROSObject = new XDomainRequest();
    //XDomainRequest doesn't support sending and receiving of cookies.
}
else
{
    CROSObject = null;
}

if(CROSObject != null)
{
    /*
        All browsers set Origin Header while sending an AJAX Request
        Some don't include this header if the AJAX request is for same domain.
    */


    CROSObject.open("GET", "http://www.qscutter.com/ajaxData.php");

    CROSObject.onload = function() {alert(CROSObject.responseText);};
    CROSObject.onerror = function() {alert("There was an error")};

    CROSObject.send();
}


</script>

http://www.qscutter.com/ajaxData.php

<?php

//Access-Control-Allow-Origin contains the response to be valid for
//requests from specific domain. set it to * for all domains. Its
//a must include header
header("Access-Control-Allow-Origin: http://www.qnimate.com");

//If withCredentials is set to true then this header needs to be
//included otherwise remove this header.
header("Access-Control-Allow-Credentials: true");

//If you want getResponseHeaders() to access other headers rather
//than the basic ones than include this header with the accessiable
//headers names.
header("Access-Control-Expose-Headers: Access-Control-Allow-Credentials, Access-Control-Allow-Origin");

echo "Response text";
?>

Let’s see an example of complex CROS:

http://www.qnimate.com/index.html

<script type="text/javascript">

var CROSObject = null;
if(typeof(XMLHttpRequest) != "undefined")
{
    CROSObject = new XMLHttpRequest();
    CROSObject.withCredentials = true;
}
else if(typeof(XDomainRequest) != "undefined")
{
    CROSObject = new XDomainRequest();
}
else
{
    CROSObject = null;
}

if(CROSObject != null)
{

    CROSObject.open("PUT", "http://www.qscutter.com/ajaxData.php");

    CROSObject.onload = function() {alert(CROSObject.responseText);};
    CROSObject.onerror = function() {alert("There was an error")};

    CROSObject.send();
}


</script>

http://www.qscutter.com/ajaxData.php

<?php
    //First check weather the request is preflight or actual. If the request if preflight check if the type of request is PUT.
    //If its a PUT request allow further operation otherwise stop it.

    //A preflight request will contain the following headers.
    //Access-Control-Request-Method is set to the method of the actual request
    //Access-Control-Request-Headers is set to a list of headers that doesn't constitute to simple CROS.
    //Origin set to the requesting URL
    if(isset($_SERVER["Access-Control-Request-Method"]))
    {
        if($_SERVER["Access-Control-Request-Method"] == "PUT")
        {
                        //you can also check Origin and Access-Control-Request-Headers for valid origin and headers

            //This is a positive response so that browser will make actual request
            header("Access-Control-Allow-Origin: " . $_SERVER["Origin"]);
            header("Access-Control-Allow-Methods: PUT");//list of allowed methods. you can comma seperate other methods also
            //header("Access-Control-Allow-Headers: X-Custom-Header");//list of allowed headers
            //header("Access-Control-Allow-Credentials: true"); //to allow cookies use
            //header("Access-Control-Max-Age: 100000");//caching preflight request and response
        }
        else
        {
            //don't allow browser to make actual request
        }
    }
    else
    {
        //Its a actual request otherwise
        if(isset($_SERVER["Origin"]))
        {
            //validate origin if you want to
            header("Access-Control-Allow-Origin: " . $_SERVER["Origin"]);
            echo "This is the response";
        }
    }

?>


Same Origin Policy for data storage

Data stored in the browser (inside localStorage and IndexedDB) are allowed to be accessed only from the same origin which stored it. Two webpages (parent and frame) from different origins can access each other’s local storage by using Cross Document Messaging API or window.name variable.

We have already seen examples of Cross Document Messaging API. Let’s see an example of bypassing Same Origin Policy using window.name variable.

http://www.qnimate.com/index.html

<iframe src="http://qscutter.com/localStorageData.php" id="myFrame" style="display: hidden"></iframe>
    <script type="text/javascript">
        window.document.getElementById("myFrame").src = "http://qnimate.com/navigate.html"; //navigating to parent origin so that it can access window name of frame
        var localStorageData = window.document.getElementById("myFrame").contentWindow.name;
    </script>

http://qscutter.com/localStorageData.php

    <script type="text/javascript">
        window.name = localStorage.getItem("storedData");
    </script>

http://qnimate.com/navigate.html

<!-- Empty Page -->

You can learn more about use of window.name from these links. Link 1Link 2


Same Origin Policy for Cookies

Same Origin Policy for cookies works different. A page can set a cookie for its own domain or any parent domain.

For example;
www.qnimate.com can set a cookie for qnimate.com.
www.blog.qnimate.com can set cookies for blog.qnimate.com and qnimate.com.
blog.qnimate.com cannot set cookie for news.qnimate.com because news.qnimate.com is not a parent of blog.qnimate.com.

Note that a page cannot set cookie for public suffix. For example www.qnimate.com cannot set cookie for .com, .uk, .in etc.

The browser will make a cookie available to the given domain including any sub-domains.

For example;
A cookie of qnimate.com will be send to qnimate.com, www.qnimate.com and www.blog.qnimate.com.

Let’s see some code example:

http://www.qnimate.com

<?php
   //if the leave the domain parameter blank then the default is www.qnimate.com
   //this cookie will be available for blog.qnimate.com, www.qnimate.com, qnimate.com, www.blog.qnimate.com etc.
   setcookie("cookiename", "cookievalue", "100000000", "", "qnimate.com");
?>

http://www.qnimate.com

<?php
   //this cookie will be reject by the browser as its been set for all domain with .com TLD (top level domain)
   setcookie("cookiename", "cookievalue", "100000000", "", "com");
?>

Extra Note: PHP automatically adds a ‘.’ in front of the domain name in the cookie. For older browser support of setting cookie for particular domains.

For example:

http://www.qnimate.com

setcookie("cookiename", "cookievalue", "100000000", "", "www.qnimate.com");//www.qnimate.com will be replaced by .www.qnimate.com

setcookie("cookiename", "cookievalue", "100000000", "", "qnimate.com");//www.qnimate.com will be replaced by .qnimate.com

setcookie("cookiename", "cookievalue", "100000000", "");//www.qnimate.com will be replaced by .www.qnimate.com.

You can set Http-Only flags in cookies so that it cannot be accessed using JavaScript and you can also force a cookie to only be transmitted over a HTTPS connection. For example:
http://www.qnimate.com

setcookie("cookiename", "cookievalue", "100000000", "", "www.qnimate.com", true, true); //6th parameter is for setting secure transmission and 7th parameter is for setting HTTP-Only flag.


Conclusion

There are many other techniques that are employed to bypass Cross Origin Policies. The above mentioned methods are enough for any kinds of apps. If you like this post please “Like and share”.

Feb 16, 2014Narayan Prusty
Making a phonegap app look like native appUnderstanding HTML img tag
Comments: 7
  1. amit mehra
    4 years ago

    sir
    i want to know how to by pass xframe-option same origin policy

    i want to load website like amzon.com in iframe but getting error
    of same origin.
    can u provide me script how to do this without any extension or third
    party software

    thanks

    ReplyCancel
  2. Chao Yang
    4 years ago

    Good post. You discussed all the cross domain solutions in one place. Cool

    ReplyCancel
  3. protech
    5 years ago

    i cant put them together do u know any tutorial how to do that , thank you

    ReplyCancel
  4. Hoang
    6 years ago

    If the site A use the same origin policy, and I want to bypass its, do I have always ask site A for permission? Can I just do these things alone?

    ReplyCancel
  5. david
    7 years ago

    Great article!! I like it a lot. How to retrieve the DOM values of a cross domain iframe page? Could you share some of your ideas?

    For example, I’ve got a parent page of mypage.com, which has an iframe page from hispage.com. How to retrieve or listen to the DOM values of the iframe page?

    Any help would be appreciated. Thank you!

    ReplyCancel
  6. Travis
    7 years ago

    Great article! I think it’s CORS, not CROS, FYI.

    ReplyCancel
    • Narayan Prusty
      7 years ago

      Changed that. Thanks :)

      ReplyCancel

Leave a Reply to amit mehra Cancel reply

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax

Narayan Prusty

I am a software engineer specialising in Blockchain, DevOps and Go/JavaScript. This is my personal blog where I write about things that I learn and feel interesting to share.

Image8 years ago 12 Comments Web Securitybrowser restrictions, cookies, dom manipulation, xmlhttprequest
Share this
0
GooglePlus
0
Facebook
0
Twitter
0
Linkedin
  • Same origin policy for accessing DOM
  • Same Origin Policy for AJAX
  • Same Origin Policy for data storage
  • Same Origin Policy for Cookies
Related Articles
  • Content Security Policy Tutorial with Examples
  • Multithreading In HTML5 Using Web Workers
  • Customizing WordPress Admin Toolbar
  • How Does HTTP Authentication Work?
  • Asymmetric Encryption using Web Cryptography API
Our Sponsor
My Books

2014 - 2015 © QNimate
All tutorials MIT license