Durable Objects

By YUI TeamMay 24th, 2008

Cooperating applications, such as mashups, must be able to exchange objects
with robust interfaces. An object must be able to encapsulate its state such
that the state can be modified only as permitted by its own methods.

JavaScript’s objects are soft and currently the language does not include any
means to harden them, so an attacker can easily access the fields directly and
replace the methods with his own.

Fortunately, JavaScript provides the means to construct durable objects
that can perfectly guard their state by using a variation of the Module Pattern.
You’ll recall that the Module Pattern makes it possible to make an object
with privileged methods. Privileged methods are able to access the private
state of the constructor’s closure. By adding one simple rule, we can easily
generate secure objects:

A durable object contains no visible data members, and its methods use neither this nor that.

This is a template for a durable constructor:

function durable(parameters) {
    var that = {} or the product of another durable constructor;

    var private variables;

    function method() {
        …
    }

    that.method = method;
    return that;
}

Define all of your methods as private methods. The methods you choose to
expose to the public get copied into that. None of the functions defined or
inherited make use of that or this.

We can give the object created by the durable constructor to untrusted code.
That code will be unable to get direct access to the private state. It can
replace the methods with its own methods, but that only reduces the usefulness
of the object to the attacker. It does not weaken or confuse the object. Each method is a capability. The object is just a collection of capabilities.

Durable objects allow code from multiple (possibly untrusted) parties to
cooperate. Durable objects can be expressed in a safe subset of JavaScript,
such as ADsafe or Cajita.

12 Comments

  1. I don’t think this pattern alone is enough to ensure privacy. I don’t think privacy can every be complete.

    Here is an idea for one hack off the top of my head that worked in Firefox.

    <script type=”text/javascript”>
    function durable() {
    var that = {};
    var a = 25;
    return that;
    }
    </script>

    <script type=”text/javascript”>
    var foo = durable();
    console.log(foo.a); // undefined
    </script>

    <script type=”text/javascript”>
    var scripts = document.getElementsByTagName(‘script’);

    for (var i=0, ilen=scripts.length; i<ilen; i++) {
    var script = scripts[i];
    var code = script.innerHTML;
    if (code.match(/return that/)) {
    setTimeout(code.replace(/return that/, “that.a = a;return that”), 10);
    }
    }

    </script>

    <script type=”text/javascript”>
    window.onload = function() {
    var foo = durable();
    console.log(foo.a); // 25
    };
    </script>

    Another example is if the script that a hacker wants to exploit is available through XHR (i.e. same origin) then the hacker could obtain the script content through XHR instead of innerHTML like in the above example.

  2. Nifty idea! Thanks Douglas.

    In addition to the no “this or that” rule, it’s also important to use global variables carefully, especially methods in the standard library. A silly example:

    function durable(params) {
    var that = {};
    var secret = {"a":"b"};
    function method() {var x=[]; x.push(secret);}
    that.method = method;
    return that;
    }

    A consumer of the durable object could gain access to the private “secret” variable by overriding Array/push:

    var y = new durable(),
    evil;
    Array.prototype.push = function(x) {evil=x;}
    y.method(); // evil now points to secret!

    In addition, one has to be careful with return values. If you return a reference to a private variable the consumer code can then trivially manipulate that variable. Using the previous example, if durable/method simply returned secret an attacker could then do something like this:

    var y = new durable();
    var evil = y.method(); // evil now points to secret

    The avoid this problem, always return values or references to method variables (as opposed to private class variables). If you do need to return private class variables, duplicate them first and return the copy.

  3. The Kerckhoffs’s Principle tells us that we should not be putting secrets in the source of the programs, and we should not be inconvenienced by the enemy reading the source of our programs.

  4. Peter,

    Your security cannot depend on your global variables if the attacker has access to your global variables, including your global functions and constructors. An attacker can trivially replace your functions with his.

    Try your attack under ADsafe. The attacker does not get access to your global durable function. The attacker does not get access to the DOM so he cannot examine the script tags. The attacker does get access to the ADSAFE object which could contain functions that facilitate interwidget communication, including the exchange of durable objects.

  5. Douglas: Thanks for the reply.

    Re Kerckhoffs’ Principle: definitely agree.

    I should have chosen the variable name “secret” more carefully, perhaps calling it “private,” or simply “state.” The point was that one has to be careful not to expose references to private variables by one means or another, as this will allow a third party to manipulate the durable object’s state directly. As you mentioned, projects like Caja and ADSafe can address (pun intended) these additional concerns.

  6. Is there any mechanism for protecting private methods defined on the prototype of an object?

  7. There are no private methods in the prototype. All members, including all methods, are public.

  8. Douglas,
    What exactly is the difference between what you outlined in the original article, specifically returning “that”, and doing this?

    var Durable = function() {
    var a = 2;
    var b = 4;
    this.getA = function() {
    return a;
    }
    this.getB = function() {
    return b;
    }
    }

    TIA,
    Billy

  9. Rytis Daugirdas said:
    May 28, 2008 at 8:12 am

    But what about inheritance? How would you inherit properties/methods from another “durable” object?

  10. I agree with Billy, what is the difference between what you propose and instantiating an instance of a constructor with private members?

  11. Billy,

    Suppose you have a method C that calls this.A and this.B. If an attacker replaces your methods with his, then C will be compromised. Function C would be vulnerable if it used this.

    Rytis,

    Inheritance is obtained by calling another durable constructor.

    var that = another_constructor();

  12. [...] This article carries this idea further to create “Durable” objects — objects that, even though they have publicly accessible methods cannot have them switched out by another script. [...]