6.858 Fall 2011 Lab 6: Javascript isolation

Handed out: Thursday, November 10, 2011
Due: Wednesday, November 23, 2011 (11:59pm)

Introduction

In this lab, you will implement a system to allow a limited set of Javascript to execute as part of zoobar user profiles. You will implement a combination of static rewriting and dynamic sandboxing to ensure that code running as part of the profile cannot modify the rest of the page, but yet it can make some changes to HTML elements that were part of the profile itself.

To give you an example of the kind of profile code that we will support, a user should be able to place the following code in their zoobar profile:

<div id="a">x</div>
<div id="b">x</div>
<div id="c">scrolling message.. </div>
<div id="count"></div>
<script>
    var count = 0;

    function flip(a, b) {
        document.getElementById(a).innerHTML = "nothing here";
        document.getElementById(b).innerHTML = "-- click me! --";
        var bump = function (x) { return x+1; }
        count = bump(count);
        document.getElementById('count').innerHTML = 'click count: ' + count;
    }

    flip('a', 'b');
    document.getElementById('a').onclick = function() { flip('a', 'b'); };
    document.getElementById('b').onclick = function() { flip('b', 'a'); };

    function scroll(id) {
        var s = document.getElementById(id).innerHTML;
        var ns = s.substring(1) + s[0];
        document.getElementById(id).innerHTML = ns;
        setTimeout(function() { scroll(id); }, 100);
    }

    scroll('c');
</script>

and get a profile that looks like the following:

x
x
scrolling message..

You will build an HTML/Javascript rewriter that will ensure that this code cannot tamper with the rest of the page, steal the cookies, etc.

The system you will be building will be a simpler version of Facebook's FBJS system. You may find it useful to refer to their documentation to understand how their system works, or refer to the paper on Run-Time Enforcement of Secure JavaScript Subsets. Note that Javascript isolation in general is a very difficult problem, and most systems that have been developed have historically turned out to be insecure in a variety of ways. Although we are not aware of any vulnerabilities in the system that you will be building in this lab assignment, it has not been thoroughly vetted or analyzed, and could very well have some subtle holes in it. (If you find any, let us know!)

To get started, you will need to install some additional software in your 6.858 VM to perform HTML and Javascript rewriting, as well as to test the resulting system using the Firefox browser. Type the following commands into your VM shell as root:

root@vm-6858:~# apt-get update
Hit http://ubuntu.media.mit.edu lucid Release.gpg
...
Fetched 1,564kB in 2s (650kB/s) 
Reading package lists... Done
root@vm-6858:~# apt-get install python-lxml firefox xvfb
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following extra packages will be installed:
  ...
The following NEW packages will be installed:
  ...
1 upgraded, 165 newly installed, 0 to remove and 134 not upgraded.
Need to get 71.9MB of archives.
After this operation, 287MB of additional disk space will be used.
Do you want to continue [Y/n]? Y
...
root@vm-6858:~# easy_install slimit
Searching for slimit
Reading http://pypi.python.org/simple/slimit/
Reading http://slimit.org
Best match: slimit 0.5.5
Downloading http://pypi.python.org/packages/source/s/slimit/slimit-0.5.5.zip#md5=0f77cb80d9b06f364afb9e4ffb8d6ff7
...
Finished processing dependencies for slimit
root@vm-6858:~# 

Now, log in as the httpd user, check in any changes you may have made for lab 5, and fetch the new code for lab 6. Note that, for simplicity, you do not need to integrate changes from previous labs into this lab; we will focus just on rewriting HTML code in profiles for now.

httpd@vm-6858:~$ cd lab 
httpd@vm-6858:~/lab$ git commit -am 'my solution to lab5' 
[lab5 dc6f228] my solution to lab5
 1 files changed, 1 insertions(+), 0 deletions(-)
httpd@vm-6858:~/lab$ git pull 
Already up-to-date.
httpd@vm-6858:~/lab$ git checkout -b lab6 origin/lab6 
Branch lab6 set up to track remote branch lab6 from origin.
Switched to a new branch 'lab6'
httpd@vm-6858:~/lab$ 

Now, build and install this code as before. Since the code for lab 6 differs from the code for previous labs, be sure to remove the /jail directory and start from scratch for this lab:

httpd@vm-6858:~/lab$ make clean
rm -f *.o *.pyc *.bin zookld zookfs zookd zooksvc *.log
httpd@vm-6858:~/lab$ make
...
httpd@vm-6858:~/lab$ sudo rm -rf /jail
[sudo] password for httpd: 6858
httpd@vm-6858:~/lab$ sudo make setup
./chroot-setup.sh
...
httpd@vm-6858:~/lab$ 

Part 1: Javascript rewriting

To understand how we will isolate Javascript code, let's first examine the new code in this lab. We have implemented a new function, called filter_html, in zoobar/htmlfilter.py, which sanitizes user profiles. This function is invoked from users.py on each user profile. The filter_html function does three things, as follows.

We have constructed a number of test cases to help you debug your Javascript sandboxing system. They are stored in profiles, and include the sample profile above with the annoying scrolling message (demo.html), an automated test case checking that this example profile works (good-all.html), and ten different malicious profiles that you will need to confine (bad-00-eval.html through bad-09-replace-proto.html).

You can invoke the HTML / Javascript rewriter by running zoobar/filter-test.py; it reads profile code as input and prints out sandboxed HTML and Javascript. For example:

httpd@vm-6858:~/lab$ ./zoobar/filter-test.py < ./profiles/bad-00-eval.html 
...
var s = "window.location = 'http://localhost:8900/test-bad';";
eval(s);</script></div>
httpd@vm-6858:~/lab$ 

To isolate Javascript, you will take the following approach:

Exercise 1. Implement Javascript sandboxing as described above. You will need to modify lab6visitor.py and libcode in htmlfilter.py.

Make sure that your sandbox works correctly with the demo.html profile, and stops the attacks in bad-*.html profiles. You can test this profile code by uploading it into (and viewing it through) the zoobar site on your VM. Alternatively, you can manually test it by running the profile code through ./zoobar/filter-test.py (as shown above), and then loading the resulting HTML code in your browser.

You can check whether your system works correctly by running make check. This can take some time, because it spawns a fresh Firefox web browser in your VM to check each profile. If your profile does not work correctly, the script aborts after a 30-second timeout. If your VM is particularly slow, and you find that this timeout fires prematurely, you can increase this timeout in test-url.sh (e.g., change the sleep 30 command to sleep 120).

You are done! Run make handin and follow instructions to upload the resulting file.