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
thisnorthat.
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.
May 24, 2008 at 3:44 pm
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.
May 24, 2008 at 6:21 pm
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.
May 25, 2008 at 5:40 am
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.
May 25, 2008 at 7:08 am
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.
May 25, 2008 at 7:55 am
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.
May 25, 2008 at 2:58 pm
Is there any mechanism for protecting private methods defined on the prototype of an object?
May 25, 2008 at 3:03 pm
There are no private methods in the prototype. All members, including all methods, are public.
May 28, 2008 at 5:24 am
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
May 28, 2008 at 8:12 am
But what about inheritance? How would you inherit properties/methods from another “durable” object?
May 29, 2008 at 3:21 am
I agree with Billy, what is the difference between what you propose and instantiating an instance of a constructor with private members?
June 2, 2008 at 11:22 am
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();
March 25, 2010 at 7:18 pm
[...] 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. [...]