Blog


postMessage API Changes

It's been a little while since I last wrote about Cross-Window Messaging in Firefox 3 using postMessage and since that time it's since a few API updates.

Specifically the postMessage API has become much simpler and has stronger security brought into mind.

If you're unfamiliar with postMessage here's a quick re-cap: It's a way to communicate simple string-based messages across browser windows (this includes frames, iframes, and popups). It's a part of HTML 5 specification and is included in Firefox 3, Internet Explorer 8, WebKit Nightlies, and Opera 9.5.

Here's the revised process works using the final postMessage API (currently only works in Firefox 3):

Sending

Sending is still done by calling the postMessage method on a window object. The one addition is that an extra targetOrigin argument is now required. This argument allows you to specify the exact origin that you're expecting this message to reach (this can help prevent malicious attempts to redirect the contents of frames to intercepting pages).

It's highly recommended that you provide an origin, but if you don't wish to you can specify "*" instead (which will work for any origin).

Demo: http://ejohn.org/apps/message/

<iframe src="http://dev.jquery.com/~john/message/" id="iframe"></iframe>
<form id="form">
  <input type="text" id="msg" value="Message to send"/>
  <input type="submit"/>
</form>
<script>
window.onload = function(){
        var win = document.getElementById("iframe").contentWindow;
        document.getElementById("form").onsubmit = function(e){
                win.postMessage(
                        document.getElementById("msg").value,
                        "http://dev.jquery.com"
                );
                e.preventDefault();
        };
};
</script>

Receiving

The primary change to receiving is that you must now listen for the incoming event on the window object, instead of the document. This is a smart API change (keeping document/window straight would've surely caused implementation problems).

Additionally, in the incoming event object, there use to be a number of properties made available for determining the origin of the request. Now, however, there is only a single property: event.origin. This property contains the base origin from which the request is coming.

For example in the above demo the full URL is "http://ejohn.org/apps/message/" but the event.origin is just "http://ejohn.org". It's highly recommended that you verify the incoming origin of the request in order to prevent any malicious attempts to inject data.

Additionally, even though it's not done below, it's important to do some validation on the incoming message contents. It's entirely possible that the origin page may have been compromised so you'll need to take that into consideration.

Demo: http://dev.jquery.com/~john/message/ (Use the above demo to see this page in action)

<b>This iframe is located on dev.jquery.com</b>
<div id="test">Send me a message!</div>
<script>
window.addEventListener("message", function(e){
        if ( e.origin !== "http://ejohn.org" )
                return;

        document.getElementById("test").textContent = e.origin + " said: " + e.data;
}, false);
</script>

I'm pleased with these changes and I'm glad that there were able to make it in to Firefox 3 in time. I hope we see some more implementation convergence here as it would be really good to have all four browsers with an HTML 5 feature in it.

Tags: security, javascript, browsers, firefox

Tightened Local File Security

There's been an interesting security adjustment in Firefox 3 that'll have some, potential, ramifications in some (file://-hosted) web pages. Specifically how local files are referenced and accessed, in parent directories, has changed.

For example, previously you could create an HTML page and have it request a file in a parent directory, like so:

<html>
<head>
<title>Local File</title>
<script>
var xhr = new XMLHttpRequest();
xhr.open("GET", "../some/file.txt", true);
// ... handle the response ...
xhr.send(null);
</script>
</head>
<body></body>
</html>

However that is no longer possible (just to emphasize: This is no longer possible only on locally downloaded web pages, running in file://...) as an HTML page can no longer access files in parent directories. This includes both ../ relative URLs and file://... absolute URLs.

There's a detailed discussion in the bug ticket concerning this change. Primarily it boils down to the fact that:

Users frequently download HTML pages for a variety of reasons, HTML pages have full access to the hard drive and the ability to do cross-domain communication, this combination leads to an unsuspecting mess where malicious pages can actively try to steal user information.

This change is two-fold: It's possibly frustrating (there's bound to be some HTML page somewhere that uses XMLHttpRequest to local in local information, located above the current directory) and unavoidable (having this security concern left in place would lead to undesired situations, if they haven't already).

Generally speaking I don't think this change will affect many people - but it's just something that you should be aware of, when planning your sites for Firefox 3.

UPDATE: In the original post I interpreted the Bugzilla bug as being that ALL attempts to access parent-directory files were blocked when, in fact, only items bound by the same-origin policy are (like XMLHttpRequest). This should affect significantly few pages but it's good to be aware of.

Tags: javascript, firefox, mozilla, html, security

JavaScript-Based Injection Attacks

The Google Caja team has put forward a fantastic document on JavaScript-based injection attacks. This is a fascinating subject and one that receives little attention (but will, undoubtedly, receive more in the upcoming months and years as JavaScript receives more attention).

In their document they detail an injection attack against a SQL database (an obvious example with parallels to existing database injections). However there is another class of problems that are particularly problematic: HTML injection, by browser extensions, allowing web-based content to access privileged code in the browser.

There's a specific example from early last year where a vulnerability was discovered in Firebug, using this very attack vector. (This hasn't been an issue in a long time - I've waited to post these details until the issue had long passed.)

The details:

The vulnerability noticed in a post on GNUCITIZEN related to the escaping of object property names in Firebug. For example, you could run the following code:

console.log({'<script>alert("bing!")</script>':'exploit'})

and it would pop up an alert.

Normally, this wouldn't be a huge concern (nothing more than a bug) - but the script that was executed had all the privileges of the normal browser (for example, to be able to read and delete files).

I was notified about this issue at about 4:36pm (EST), read through the details, tried the exploit, and then set about creating a patch. At 5:32pm I fixed the particular exploit and had a patch ready. At that time I set about trying to find other instances where this exploit could also work.

How the exploit works

Firebug has some very-cool DOM creation code embedded in it. One of the fundamental differences between it and normal DOM creation code is that it creates a serialized string of HTML as output, instead of a series of DOM objects. This means that .innerHTML can be used to inject the HTML (which is blazingly fast).

The published exploit occurred in such a case where a string was being put into this DOM-serialization code, but was not having its HTML characters escaped (in reps.js):

OBJECTLINK(
  SPAN({class: "objectTitle"}, "$object|getTitle"),
    FOR("prop", "$object|propIterator",
      " $prop.name=", // The un-escaped variable
      SPAN({class: "objectPropValue"}, "$prop.value|cropString|escapeHTML")
    )
)

The fix was simple, just changing the line in question to the following:

" $prop.name|escapeHTML=",

It was at this point that I started to dig around the rest of the Firebug code base, looking for more escaping exploits. At this point Joe published Firebug 1.02 (at about 5:47pm) before I could get any of my patches to him. Looking through the changes that he made, he fixed the exact line that I mentioned before - solving the published exploit.

After some more reading I found another exploit relating to the first one. If you click the serialized version of the (exploited) object in Firebug, it would open up the DOM inspector pane, and execute the un-escaped code.

This second exploit was found in dom.js (which runs the DOM inspection pane):

TR({class: "memberRow $member.open $member.type\\Row", $hasChildren: "$member.hasChildren",
  level: "$member.level"},
  TD({class: "memberLabelCell", style: "padding-left: $member.indent\\px"},
    DIV({class: "memberLabel $member.type\\Label"}, "$member.name") // un-escaped variable
  ),
  TD({class: "memberValueCell"},
    TAG("$member.tag", {object: "$member.value"})
  )
);

That was another quick patch:

DIV({class: "memberLabel $member.type\\Label"}, "$member.name|escapeHTML")

I notified Joe at about 6:30pm (and pointed out other interesting bits of code) and he set out to see if he could find another set of exploits, as well. Before the evening was over, he was able to find one other loophole in the XMLHttpRequest spying code, and resolve it. It was at this point that he packaged up and distributed Firebug 1.03 at about 7pm, incorporating the three different escaping vulnerabilities that we were able to locate. Later on he provided a systemic fix to the whole escaping issue which has solved future injection problems.

I found the whole experience to be very exciting, and fun; getting a fix out was the top priority, and that was definitely achieved. However, knowing how and why these types of attacks can happen is important to JavaScript development, as a whole. I'm really glad that the Caja team is doing good work in getting the word out.

Tags: javascript, security, firebug

Bad Background Browser

The other day I caught this humorous image posted to Reddit, showing a Firefox update dialog popping up over a weather satellite image, live on TV:


I was amused, so I posted it to one of Mozilla's internal mailing lists - which started a renewed flurry of discussion surrounding the update manager. To start with, a bug was filed on this specific issue: don't prompt for software update unless firefox is the foreground application. Second, it was pointed out that a particular fix has already landed in Firefox 3, related to this issue: Software update dialog steals focus / wait for idle before prompting. Obviously, that's a good thing, but only the first step. So in addition to not prompting when the dialog is in the background we now, additionally, have the following bugs which are desired to be resolved:

Needless to say, this particular issue, while haphazardly amusing, will no longer be a problem in Firefox 3.

One thing that I find to be particularly interesting about this whole situation: The easier, and less painful, it is for a user to upgrade minor releases of Firefox, the more secure the browser is. (If a fix is released for a security problem and the user opts to not upgrade, they choose to remain vulnerable - which is a very bad thing.) Thus, anything that can be done to improve the quality of upgrading is considered to be a security enhancement. Security through improved user experience! I like it.

Tags: mozilla, firefox, browsers, security

Re-Securing JSON

Back in March/April of this year there was a lot of hub-bub concerning the discovery of a JSON data leak, or sorts. What it boils down to is "JavaScript is incredibly flexible, even to the degree of letting you redefine basic objects, like Array or Object itself."

For example, here's an exploit that works in Firefox 2, Opera 9, and Safari 3. It goes about redefining the global Array object then making it such that whenever a property value is set (even when the array is constructed!) the value is alerted out. In theory, a malicious script could use this technique to swipe data transmitted in JSON (via JSONP or even via an XHR+eval) and send it back to another server.

// From Joe Walker
function Array() {
  var obj = this;
  var ind = 0;
  var getNext = function(x) {
    obj[ind++] setter = getNext;
    if (x) alert("Data stolen from array: " + x.toString());
  };
  this[ind++] setter = getNext;
}
var a = ["private stuff"];
// alert("Data stolen from array: private stuff");
 

Around the time of that commotion, a bug was filed in the Mozilla bug tracker that begin to explore ways of fixing this issue. It was eventually decided that this was a specification issue and that global objects should not be able to be redefined, due to the inherent problems that they can cause. You can read more about this change, which will be a part of ECMAScript 4/JavaScript 2 in Section 1.4 of the ECMAScript 4 Incompatibilities paper [PDF].

To set about testing this new change, and bringing it into practice sooner rather than later, the Mozilla team implemented and committed a fix to be a part of Firefox 3 (and thusly, JavaScript 1.8). Well, that change landed last week and after a couple minor fires were put out, it made it into the final release of Firefox 3, Beta 2.

If you want to see the change in action, go and download a Firefox nightly and put something like this in the console:

function Array(){
  alert("hello, I found something of yours!");
}
// ERROR: redeclaration of const Array
 

You'll note that you now get the above error. This will also be the same for the following global objects:

Thus, if you attempt to redeclare any of those global objects (like I did above) you'll get the same error. Note that extending properties or prototypes of those objects have remained unchanged (they still work just fine) and this is a change that really shouldn't effect anyone (save for the malicious types!).

As always, should you spot something tricky, please feel free to file a follow-up bug to the original one (or if you need help localizing it and reproducing it, let me know).

Tags: xss, json, javascript, firefox, mozilla, security

Why Firefox 2.0.0.11 Happened So Fast

Prologue: drawImage with broken PNG draws random memory

Prior to the release of Firefox 2.0.0.10 a minor security issue was discovered in the drawImage method in the Canvas API. This particular method takes an image (in the form of an IMG DOM Element), extracts the image data, and puts it into the Canvas at the desired points. If you're interested in seeing what this method does (and aren't running 2.0.0.10) then visit the Mozilla developer demo. The issue was that if the image was corrupted in some way, drawImage would still try to read data from it and display random bits of memory instead (oops).

This was fixed and two attachments were uploaded resolving this bug. However, that's where the issue came in. When it came time to commit the changes, only the first patch landed (by mistake) which caused drawImage to become all wonky. Coupled by the fact that there wasn't an immediate regression test in place to notice the obvious error. (That being said, we're getting much better - going from very few automated tests about a year ago, to tens of thousands now.)

Nov. 26: Firefox 2.0.0.10 is released, Canvas.drawImage method is not working

Canvas users (both web applications and Firefox extensions) start to notice the following error pop up:

uncaught exception: [Exception... "Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIDOMCanvasRenderingContext2D.drawImage]" nsresult: "0x80040111 (NS_ERROR_NOT_AVAILABLE)" location: "JS frame :: drawImage.html :: anonymous :: line 12" data: no]

The obvious bug is spotted and the patch is landed. The question then became: How serious is this? In a nutshell: Very serious. A number of critical applications were using this functionality to draw parts of their UIs and having this fail made them unusable. Thus, the new question was: How fast can we get it out? The answer:

Nov. 29: Firefox 2.0.0.11 is released, fastest turnaround for a browser, yet.

So that's why you're seeing two browser updates in one week. It was a big mistake, but thankfully it was caught quickly, fixed quickly, and released quickly. And in the end, it'll be a good thing, as I'm sure it'll get some more regression tests landed in the suite.

Tags: security, firefox, browsers

JavaScript Fuzz Testing

Fuzz testing is incredibly cool. Essentially, you throw random data at a program, seeing how it responds. This has a broad range of applicability, especially so in the world of security (finding fringe cases that the program authors didn't cover, leading to exploits).

For example, if you were testing a web application, you could generate random query strings of input to send to it, to see how the site might respond (possibly detecting an exploit or XSS attack of some sort).

Jesse Ruderman just introduced a fantastic new utility for probing JavaScript implementations called jsfunfuzz. Specifically, this utility generates various JavaScript statements then executes them - seeing what the result will be.

I've actually been following the progress of this utility for a while now - seeing it's outstanding results pop up on various tickets that I've watched. At first, I didn't know about the jsfunfuzz utility and just assumed that Jesse was a wizard of developing obscure ways to break JS engines. It wasn't until that I found and looked into the tool that his various bug comments made much more sense.

The usefulness of jsfunfuzz falls into two distinct areas: Testing the security of a JavaScript implementation looking for errors capable of crashing a browser and testing the validity of a JavaScript implementation looking for syntax errors.

Security

jsfunfuzz has explicit knowledge of how JS is parsed and interpreted, so it's able to make educated guesses at how to write code that will break a browser. Because of this, over 280 bugs have been found in Mozilla thus far, with about 2 dozen of them being exploitable.

This aspect of the utility has been making some significant news lately, when it was announced at the Blackhat conference. Tons of examples of the result of this work can be found in the jsfunfuzz ticket.

Here's one statement, for example, that jsfunfuzz generated that was able to produce a security exploit in Mozilla:

js> this.x setter= new Function; this.watch('x',
  function(){}); gc(); x = {};
before 9232, after 9232, break 01205000
Bus error

Language Implementation

The second positive side-effect of this utility, and the one that I'm particularly interested in, is that of testing a JavaScript language implementation for correctness.

Update: It should be noted that 'correctness' is only hap-hazardly verified through fuzz testing (in that, no specific output is tested or verified - it simply watches for crashes or decompilation errors). It's this second group of tests (uneval-ing a code block then verifying its contents to be equivalent to the input) that are particularly handy for testing the basic syntactical validity of a JavaScript implementation - but it doesn't go much beyond that.

For example, look at this recent (large) ticket where Brendan implemented a number of speed improvements to Spidermonkey. He asked Jesse to come in and run the fuzzer to see if it could find any loose-ends, and sure enough, plenty were to be found:

js> [].map(1 for (x in []))
Assertion failure: *pc == JSOP_NULL, at jsopcode.c:3862

--

js> (4).__lookupGetter__('w')
Crash [@ obj_lookupGetter]

--

js> f = function() { new (delete y) }
function () {
    new delete y;
}
js> eval(uneval(f))
typein:2: SyntaxError: syntax error:
typein:2: (function () {new delete y;})
typein:2: ..................^

--

(The following script caused a crash [@ js_ValueToString].)

function c(gen){
  Iterator;
  '' + gen;
  for (var i in gen());
}
function gen(){
  ({}).hasOwnProperty();
  yield;
}
c(gen);

Now, all of this is not for waste. What happens now is that for each of these issues that jsfunfuzz discovered (albeit in a patched version of the JS engine) can be converted into test cases, which will be re-run every time a new build of the browser is generated. This is absolutely fantastic.

It's pretty incredible how a common security testing tool can become good at testing, and generating test cases for, a JavaScript language implementation. This is especially important as development of ECMAScript 4-compliant language implementations start to appear - as new ways to test and break them will need to be discovered; and fuzz testing looks to be a fantastic way to achieve that.

Tags: ecmascript, language, programming, security, javascript, mozilla

JavaScript Spider

I came across a site, today, that claimed to be a "new JavaScript attack vector" called the: JavaScript Spider. The result, however, is completely laughable. According to the web site:

The JavaScript Spider is the first implementation of a proof of concept tool which shows that Javascript can be in fact quite dangerous. This implementation depends on proxydrop.com but other proxies are possible as well: Google Translate is one of them. Keep in mind that the tool spiders only the first level.

I don’t think this guy knows what “attack vector” means. Using a publicly-accessible anonymous proxy is hardly a security concern - especially considering that none of the user’s personal information is being passed along.

Honestly, the only thing that that he “discovered” (and that was just something that he noticed, as the world has passed him by) is that publicly-accessible anonymous proxies can be used for “bad” things. Uhhh... duh?

Seriously, if every use of a server-side proxy was considered to be a client-side security risk, then we'd have a much larger issue on our hands. This quote, alone, helps to sum up his ignorance: "Javascript can be in fact quite dangerous."

Tags: security, browsers, javascript

· « Previous entries

Current Projects

jQuery JavaScript Library

jQuery

Comprehensive DOM, Event, Animation, and Ajax JavaScript Library.

Recent Projects

Pro JavaScript Techniques

JavaScript Book

The best techniques for professional JavaScript. Published by Apress.


Hosting provided by the cool dudes at Engine Yard.