Caja

(draft)

Overview

How can you write secure mashups in Javascript?

Mashups

Traditional way to include third-party "rich" content:

* The traditional way to do sandboxing was using iframes hosted on a different domain - these have a lot of shortcomings - iframes are rectangular - there's limited ability to co-operate between gadgets - they don't actually work either * Defensive code problem - shared global namespace * HTTP-Only cookies are not needed

Mashups

Traditional way to include third-party "rich" content:

Mashups

Traditional way to include third-party "rich" content:

* The traditional way to do sandboxing was using iframes hosted on a different domain - these have a lot of shortcomings - iframes are rectangular - there's limited ability to co-operate between gadgets - they don't actually work either * Defensive code problem - shared global namespace

LOLcat Search

Two cooperating gadgets:

LOLcat Search


Example Attack: Redirection

top.location = "http://www.thinkfu.com/evil.gif";
You want to allow gadgets in your page but browsers allow any gadget (including one that is in an iframe) to access and navigate the browser window. For example, a gadget can redirect the container to a phishing site to steal your password. Caja does not enforce a policy of its own. Instead it gives containers stricter control over a gadget can do. For example, it allows the container to decide whether a gadget can read or set variables such as top.location. A careful choice of policy allows a container to protect its users from being unwittingly redirected to phishing and malware sites.

Example Attack: History Sniffing

.co
var computedStyle = document.defaultView.getComputedStyle(link, null);
var computedColor = computedStyle.getPropertyValue('color');
var visited = computedColor == 'rgb(0, 0, 0)' ? "Yes!" : "Unknown";
When you visit a website, your browser helpfully colors links to that site with a different color. Unfortunately a malicious gadget can use this computed style to detect if you have visited particular sites. In this way, a malicious gadget try to determine your gender, your news tastes, your political leaning, the name of your bank and other sensitive information by analyzing the sites you visit. By default Caja protects users against such leakage of information by not granting access to computed styles.

Example Attack: Cookie Stealing

document.getElementById('cookie').innerHTML = document.cookie;
You want to inline gadgets in your page but you don't want it to steal your viewer's cookies. In this example, you can see if a gadget you use sets cookies and if a malicious gadget can access it. Caja disallows access to any variable which the container does not explicitly grant a gadget access to. Unless a container explicitly grants a gadget access to your cookies, a gadget is unable to access it.

Example Attack: Script Injection

                    var blogComment = document.createElement('div');
                    blogComment.innerHTML = document.getElementById('submittedComment').value;
                    document.getElementById("comments").appendChild(blogComment);
You want to allow a user to enter comments in your blog using HTML but you don't want them to be able to enter scripts which steal cookies of other readers of your blog. In this example, user input is being assigned directly to innerHTML. On some browsers this has no effect but on IE, this will result in the embedded script being executed. Caja prevents such attacks by sanitizing strings before inserting them into the DOM. There are regularly circumstances where you want to embed third party code in your application. The most obvious cases are in social networks like Orkut, Facebook, iGoogle, YAP. But many of you as developers of other applications, as authors of blogs, of wikis, of applications where you want javascript plugins, and of applications that display ads, you regularly need to allow third party gadgets to be embedded in your application.

Caja — Securing WebApps

A principled secure framework for mashups that runs in existing browsers and is usable by non security-experts.


http://code.google.com/p/google-caja/

Caja:

Goals

Co-operating Gadgets

var searchEngine = new SearchEngine();

  // Provide both modules an interface to AJAX Search APIs.
searchBoxImports.searchEngine = kittensImports.searchEngine = searchEngine;

  // Allow searchBoxImports to talk to kittens.
searchBoxImports.resultConsumer = kittensImports.showKitten;

Source Code Rewriting

location = 'http://evil.com/';
IMPORTS___.location = 'http://evil.com/';

Globals rewritten to point to a per-gadget object. Authority not "ambiently" available.


document.createElement('script');
IMPORTS___.document.createElement('script');

"Tamed" document object looks, smells, and tastes like the real DOM, but can whitelist elements and rewrite attributes.

Source Code Rewriting

Unfortunately closed functions are not enough

Object-Capabilities Build on Good Software Development Practices

Separation of DutiesSeparation of Authority
Information hidingEncapsulation
Message PassingAuthorization
Dependency InjectionAuthority Injection

POLA
(Principle of Least Authority)

Cajita: Remove the knives from javascript

  • Removes from javascript
    • eval
    • with
    • this
    • variable deletion
    • Complicated coercing rules surrounding == and !=
  • Adds to javascript
    • cajita.freeze
    • immutable objects
  • Interoperates well with existing browser api



  • A decent language to program in!
  • Offensive Code Problem ✓
  • Legacy Tools Problem ✓
  • Defensive Code Problem ✓
  • Legacy Code Problem

Valija: Add toy knives right back in again

Solving All Four Goals In One Step Is Hard

Instead solve in steps

  • Make the target language cajita
    • Take advantage of the security guarantees
  • Implement the lost functionality of javascript in cajita
  • Compile legacy javascript → cajita → secure third-party javascript
  • Offensive Code Problem ✓
  • Legacy Tools Problem ✓
  • Defensive Code Problem ✓
  • Legacy Code Problem ✓

Taming

                ___.grantFunc(imports.console, 'log');
                ___.grantRead(imports.top, 'location');
                ___.grantSet(imports.document, 'cookie');
                ___.useGetHandler(imports.window, 'alert', function(msg) {
                    if (throttle()) alert(trueName() + msg);
                 } );
Time of check vs time of use Eich: not sure if rewriting systems make sense - probably don't want rewriting rules so much SES: Secure ecmascript Venkat delivery via dom api

URI Rewriting

                <img src="http://www.evil.com/overflow.jpg" >
<img src="http://www.goodguy.com/?sanitize=www.evil.com/overflow.jpg&mimeType=image/*" >

Lessons Learnt

Summary

Just the beginning...

Try Out Caja

Questions?