One of the most interesting parts of the JavaScript language is the prototype property, which underpins the language's object-oriented inheritance. In JavaScript, functions are a specialized kind of object; every function (and indeed every JavaScript object) has a prototype property that refers to a predefined prototype object, which comes into play when the function is used as a constructor with the new operator.
Prototypes are not limited to user-defined classes. Even built-in JavaScript classes have prototype properties, and you can assign values to them.
This is extremely powerful. It is also extremely dangerous. Using prototyping, an attacker can hijack standard functions in a way that breaks security without causing any error message. Browsers try to prohibit this by dropping the prototype property for some of their internal functions, but there's a way around that protection.
At the 23rd Chaos Communication Congress, held at the end of December in Berlin, Stefano Di Paola and Giorgio Fedon gave a talk called Subverting AJAX (PDF), in which they explained exactly how to do this. Coupled with a cross-site scripting attack and a cleverly crafted phishing email, such an attack could turn an AJAX application into a keylogger with a man-in-the-middle attack strategy. Consider the following diagram, from Di Paola and Fedon's paper:
What's happening here is that the attacker has hijacked the browser's XMLHttpRequest object, and wrapped it with his own keylogging logic. How hard is this to do? Not very hard at all. The key code would be:
var xmlreqc=XMLHttpRequest;
XMLHttpRequest = function() {
this.xml = new xmlreqc();
return this;
}
This is fairly subtle, but it's devastating. XMLHttpRequest has been redefined to be a wrapper for itself. Any time a new instance of XMLHttpRequest is intended to be created in subsequent code, the wrapper method will be created instead. It now doesn't matter that the original XMLHttpRequest function didn't have a prototype property: the new one does.
Once the attacker has prototypes at his disposal, he can redefine key methods. For example, he can redefine the send method to sniff and/or modify the content, as shown in the figure above and the following code:
XMLHttpRequest.prototype.send = function (pay){
// Hijacked .send
sniff("Hijacked: "+pay); //log the original message
pay=HijackRequest(pay); //change the message
return this.xml.send(pay); //send it on
}
The classic response to this kind of exploit would be "disable JavaScript in your browser." Unfortunately, AJAX applications inherently require JavaScript, and most people really like the improved user experience of AJAX applications compared to conventional Web applications.
I don't have a good solution, other than constant vigilance on the part of every author and user of AJAX applications. We're back to "Don't talk to strangers," kids. In the words of the original CERT bulletin about cross-site scripting,
"users can gain some protection by being selective about how they initially visit a Web site. Typing addresses directly into the browser (or using securely stored local bookmarks) is likely to be the safest way of connecting to a site."
(Thanks and a tip of the hat to Roy M. Silvernail, who alerted me to this exploit.)
Posted by Martin Heller on January 8, 2007 10:24 AM








