C S: Specifying and Enforcing Fine-Grained Security Policies For Javascript in The Browser
C S: Specifying and Enforcing Fine-Grained Security Policies For Javascript in The Browser
8ody of funcLlon
me1.postMessagggggggg
me2 postMessag ag agggggg ag
c
f
m
m
adv ad ad ad ad ad ad ad ad ad d |ce
444444444e6 e6 e6 e6 e6 e6 e6666 0xff4474
.postMessag ag ag ag aggg ag ag ag
Advlce lookup Lable
Figure 5: Foreign function (e.g., DOM) interpositioning.
are not exposed as JavaScript object elds; they are only
visible within the C++ interpreter.
We modied the execution of a user-dened function to
rst check whether advice was registered and enabled. If
so, execution proceeds by running the advice function. This
interpositioning is fast in practice because the function to
jump into has been resolved at registration time and the stack
is already set up for a function call, with the exception of
the function being advised being passed as a parameter on
the stack.
Native functions. JavaScript supports a standard set of func-
tions, like eval and its math libraries, that might be handled
more efciently than more general user-dened functions.
As with user-dened functions, there is an explicit object
in the interpreter for every such function: interpositioning is
analogous to that for user-dened functions.
Foreign functions. A JavaScript engine is typically em-
bedded within a larger hosting application, like a browser,
and the host provides functions to the interpreter, which,
in turn, exposes them to scripts. For example, Internet
Explorer 8 provides COM functions to the JavaScript in-
terpreter for cross-frame communication, which are reach-
able through the window and document objects, such as
window.postMessage.
While such a function is still perceived by the script
developer as a JavaScript closure, the hosting environment
actually manages the underlying representation. The prob-
lem is that Internet Explorer 8s JavaScript interpreter simply
represents such functions with a single pointer; there is no
object to which we can directly bind advice.
Our solution is to build a translation table on demand.
As shown in Figure 5, whenever a script binds advice to an
external function, the mapping from a function pointer to the
corresponding advice function is added to the table. Once a
function call is resolved to a foreign function, a check is rst
484
Authorized licensed use limited to: Jaypee Institute of Technology. Downloaded on July 22,2010 at 07:16:10 UTC from IEEE Xplore. Restrictions apply.
made whether advice has been registered: a hit causes the
advice to be called, while a miss continues the regular ow.
The size of the table is bounded by the number of registered
external functions to advise. We believe that compared
to alternative implementation strategies, such as using fat
pointers, our solution involves minimal instrumentation.
B. Blessing and Advice Optimizations
Consider simple pass-through advice that attempts to
resume the originally invoked function:
function add1 (x) { return x + 1; }
function ok (f, x) { return f(x); }
around(add1, ok);
var three = add1(2);
Upon the initial call to add1, because advice is registered
for it, ok will be called instead. Executing ok will call f,
which is bound to add1, leading to innite recursion.
To address this issue, we provide two functions, bless
and curse, that temporarily manipulate the advice-set bit.
A status bit is associated with every closure. Calling bless
disables advice and calling an advised function checks it,
and if the bit is disabled, re-enables the advice bit for the
next call, but does not dispatch to the advice function for the
current one. The above advice function would be rewritten:
function ok(f, x) { bless(); return f(x); }
However, in our experimentation with CONSCRIPT, we
discovered that requiring an explicit call to bless, beyond
being verbose, introduces an extra script-level function call
for the typical case of a policy passing and therefore incurs a
performance penalty. We perform auto-blessing by default:
we assume advice will dispatch to the raw function and thus
disable the advice upon dispatch. For the typical case, the
advice code no longer needs to call bless.
Automatically ipping the advice bit upon advice invo-
cation introduces a new concern. If the raw function is not
called, such as for throwing an exception in response to a
policy violation, the advice must be reenabled. We provide
the function curse to turn the bit back on. For example,
to only permit calls to add1 with numeric parameters, one
would write:
function onlyNum (f, x) {
if (typeof x == number) return f(x);
else { curse(); throw exn; } }
around(add1, onlyNum);
Auto-blessing also results in a much lower performance
overhead than the alternatives. We assess the performance
of blessing and auto-blessing in Section VII.
C. Advising Script Introduction
Controlling the way new scripts are added to the Web
application is paramount to application security. For the
specic pointcut of script introduction, we modied the
engine to support a different form of around. Before sending
the source of a script to the parser etc., if script advice is
registered, it is sent to the advice function:
var glbl = this;
aroundScript(function (src) {
return (glbl == this) ? "" : src; });
In this case, the code about to be introduced is re-
ferred to by parameter src. As shown above, to de-
termine whether the source is associated with a new
<SCRIPT> tag or code inlined into an HTML tag (e.g.,
<a onclick ="alert(hello)"/>, advice must check
the object to which the this is bound. We cannot reuse
around because the deep function corresponding to code
injection is not exposed to JavaScript so its use cannot be
directly secured.
The string returned by the advice function will be passed
through the parser instead. This simple advice mechanism
could be used to completely change the way scripts are
interpreted. For instance, Caja-style rewriting [7] or AdSafe-
style subset checking [14] could be applied to the script
before being passed to the JavaScript engine: unlike previous
approaches that must account for all code injection points, all
dynamically introduced code is directly subject to mediation,
simplifying implementation.
IV. SECURING ADVICE
In this section, we consider attacks against CONSCRIPT
advice policies. Auditing policies published by other re-
searchers, we found that they are quite tricky to get right.
This is true even for policies consisting of only a few lines of
JavaScript [2, 3]. While the idea of aspects is by no means
new [15], in an adversarial environment, aspects are subject
to a host of difcult issues.
In our attack model, we distinguish between kernel code
(code loaded before an untrusted library) and user code (un-
trusted libraries that may execute after the loading sequence).
It is our intention to protect against advice tampering, i.e.
user code that attempts to interfere with the way advice is
applied and followed at runtime by tampering with code or
data. Our approach is to slightly modify the interpreter to
enable isolated reasoning about policies. In Section IV-C,
we discuss a custom static analysis to verify that policies
are safe against common attacks.
A. Motivating Example: A Whitelist Policy
Consider the policy in Figure 6a that attempts to use
a whitelist to limit which frames may be messaged. Us-
ing CONSCRIPTs deep around advice eliminates concerns
about alternate aliases for postMessage. However, there are
further exploitable attack vectors:
1. toString redenition: The target parameter is ex-
pected to be a string but this is never checked, so the attacker
may foil the whitelist check with a clever use of a custom
toString method:
var count = 0;
frame1.postMessage("1",
{toString: function () {
count++;
485
Authorized licensed use limited to: Jaypee Institute of Technology. Downloaded on July 22,2010 at 07:16:10 UTC from IEEE Xplore. Restrictions apply.
var okOrigin = {"http://www.google.com": true};
around(window.postMessage,
function (post, msg, target) {
if (!okOrigin[target]) {
curse(); throw err;
} else return post.call(this, msg, target); });
let okOrigin = {"http://www.google.com": true };
around(window.postMessage,
function (post, msg, target) {
let t = toPrimitive(target);
if (!hasProp(okOrigin, t)) {
curse(); throw err;
} else return uCall(this, post, msg, t); });
Figure 6: Vulnerable (a) and secure version (b) of the same intended whitelisting policy. Policy (b) passes the type checker.
return count == 1 ? "http://www.google.com"
: "evil.com" });
2. Function.prototype poisoning:
Function.prototype may be modied to have method
call invoke the auto-blessed function:
Function.prototype.call =
function () { window.postMessage("1", "evil.com"); }
frame1.postMessage("1", "http://www.google.com");
3. Object.prototype poisoning: New entries may be
added to Object.prototype, including one whitelisting the
URL "evil.com":
Object.prototype["evil.com"] = true;
frame1.postMessage("1", "evil.com");
4. Malicious getters: Combining poisoning attack 3 with a
syntactically-invisible malicious getter function, an attacker
may even gain access to the whitelist object and edit it:
Object.prototype.__defineGetter__("evil", function () {
delete this["http://www.google.com"]; });
frame1.postMessage("1", "evil");
While aspects eliminate a common source of error in se-
curing APIs targeting the appropriate functionality
as these examples show, writing correct policy logic is
still very tricky. Our solution is to make interpreter-level
modications that enable isolated reasoning and then provide
a static analysis for policies. Figure 6b shows a version of
the original policy that passes our checker and is also not
vulnerable with respect to the attacks listed above.
B. New and Removed Features
To enable modular reasoning, we slightly modify the
JavaScript interpreter. Just like the ES5s standards strict
mode [16] we eliminate dynamic constructs with and eval,
as they make static reasoning quite difcult by allowing
user code to manipulate seemingly encapsulated policy code.
For instance, JavaScript exposes a limited form of stack
inspection: if a policy calls an external helper function,
that function may use eld caller to access and modify
arguments on the stack and call functions on the stack. In
CONSCRIPT, we disallow caller access
2
.
We added a new secure calling form uCall to avoid
prototype poisoning attack 2 on call, which we can also
use to build further calls. In attack 2, the policy writer wants
to invoke call on post, but invocations of post.call(...)
2
This feature is deprecated in the upcoming JavaScript language stan-
dard [16]. In particular, Section 15.3.5.4 notes: If P is caller and v is
a strict mode Function object, throw a TypeError exception. Similar
eval restrictions needed for encapsulation are given in Section 10.4.2.1.
are subject to prototype poisoning attacks. Figure 6b demon-
strates our new primitive uCall that may be used to invoke
functions with custom this objects (post in this example)
but without prototype poisoning. Similarly, while we might
try to avoid the poisoning in attack 3 of okOrigin[target]
by writing okOrigin.hasOwnProperty(target) to check
direct (non-inherited) elds of okOrigin, we must avoid
using a poisoned hasOwnProperty. Our solution is to use
uCall to encode the safely encapsulated hasProp function:
var h = {}.hasOwnProperty();
function hasProp (o, fld) {return uCall(o, h, fld);}
Finally, to avoid type forgery attacks as in attack 1, we
provide function toPrimitive to perform the conversion
from a potentially poisoned object to a primitive type.
C. Statically Validating Policies
We propose a static verier to check for common security
holes in policies. We use a type system in which traditional
ML-style types, like arrows for functions and records for
objects, are annotated with security labels. Only policies
must type check (program code need not) and we assume
the JavaScript interpreter restrictions from Section IV-B.
Challenging current attempts to analyze JavaScript, there
is no formal semantics realistic enough to include many
of the attack vectors we have discussed yet structured and
tractable enough that anyone who is not the inventor has
been able to use; formal proofs are therefore beyond the
scope of this work. However, our system is an application
of techniques established for analyzing C and Java using
labels or qualiers [17, 18] with adaptations derived from
the (informal) ECMAScript standard and previous attempts
to tame JavaScript like Caja [7]. We also phrase our analysis
as a type system to present a concise yet reasonably thorough
case analysis that also guides implementations.
The rest of this section is organized as follows. First,
we present the safety properties checked at each term in
our system and the corresponding trust labels for reasoning
about them. Next, we summarize the underlying ML-like
type system and examine some representative rules. We also
briey discuss type inference. We refer the reader to our
technical report [19] for a more thorough presentation of
our type system.
Policy Safety. In CONSCRIPT, we protect policies against
violations of the following two properties:
1) Reference isolation: Kernel objects should not ow
to user code. E.g., the whitelist in Figure 6 may only
be referenced by policy code.
486
Authorized licensed use limited to: Jaypee Institute of Technology. Downloaded on July 22,2010 at 07:16:10 UTC from IEEE Xplore. Restrictions apply.
Label Policy-only Invocable
(u)ser object
(k)ernel environment function
protected (o)bject
Figure 7: Label properties.
2) Access path integrity of explicitly invoked func-
tions
3
: When a policy invokes a function, that function
should be known at time of policy loading. Otherwise,
the call may be subject to prototype poisoning, as with
call in Figure 6a.
Security Labels. To reason about whether any term violates
one of our properties, each one is labeled with a privilege
level: u, k, or o. The privilege level determines which (if any)
of the following two properties is enforced for a particular
value, as summarized in Figure 7:
Policy-only. The policy-only property is for reference
isolation, signaling which values user code cannot
directly reference (and, implicitly, stating user code
might have access to any other). For example, an object
representing a whitelist dened in policy code should
not leak out (Figure 6) and thus should be policy-only.
In CONSCRIPT, the opposite of being policy-only is
being a potential sink for capability leaks. For example,
if an object is not policy-only, it might be accessible
to user code, as would any of its elds. These elds
act like an escape sink towards user code; they should
not be assigned a policy-only value like a whitelist.
Label o values are policy-only (Figure 7). Only special
CONSCRIPT primitives or closures and object literals
dened in a policy are labeled o.
Invocable. The invocable property is for tracking ac-
cess path integrity at call sites. For example, function
window.postMessage in Figure 6 is accessed in the
top-level at policy denition time and thus should be
marked as invocable in the top level without concern
for hijacking. Similarly, policy-only terms are labeled
o and are never leaked: they are not hijacked and may
be invoked.
Our labels form a lattice: ( < k < u < ) ( < o < ).
For example, o terms cannot be substituted for u or k terms
during assignments. Similarly, k (invocable) terms may be
substituted for u (non-invocable) terms as fewer interactions
may be performed with u terms. We represent substitution
with ow relation L
1
L
2
, read as L
1
may ow to (or
substitute for) L
2
, such as ku and oo. Such ow checks
might be replaced with proper subtyping in future versions.
An ML-like Core Language. Our core language is an
ML-like subset of JavaScript. The base value for every
3
Stronger properties might disallow any user function invocation, which
is too draconian, or any user function invocation, which is too cumbersome
(e.g., eld access requires explicit permission due to setters and getters).
type (e.g., T
1
in T
L1
1
) is the primitive type or an ML-
like type constructor: (. . . ; fld
n
: T
Ln
n
) for a record
type, . . . T
Ln
n
T
Lo
o
for a function type, and T
L
ref
for a reference type. Note that if T
1
is a type constructor,
its component types will be labeled. We use these type
constructors to provide structure otherwise, label tracking
would be too imprecise. Primitive types cover heap values
allocated outside of policies: we do not trust external logic so
have little interest in the structure of its values. To simplify
reasoning, new primitives like around are not rst-class and,
like AdSafe [14], we statically disallow JavaScript keywords
like arguments, as detailed in our technical report [19].
Inference Rule Samples. This section examines several
examples of how labels are used in our type system.
Calling trusted foreign functions: Consider the invocation
of uCall(this, post, msg, t) in Figure 6b. uCall is for
invoking non-policy functions, but the rule must ensure that
the non-policy function has not been hijacked and that it is
not leaked a reference to policy objects:
uCall / o : T
Lo
o
Lo u
f :
L
f
L
f
= k
an : T
Ln
n
Ln u i {. . . , n}
uCall(o, f [, . . . , an]) :
u
(inner-level uCall)
We cannot use an ordinary arrow type for uCall: the
rst antecedant checks that it is truly the environments
uCall. The fourth antecedant checks that posts base type
is : uCall is not intended for policy functions. The fth
antecedant requires post to have label k, meaning it could
not have been hijacked and can thus be invoked. Using
ow relation , the third and seventh antecedants check
that this, msg, and t arguments have low enough privilege
to be allowed to ow to user code (label u). As f is not a
policy function, we know the result of uCall is a primitive
(e.g., of non-policy origin) value of type .
Our system syntactically distinguishes top-level code,
executed when advice is registered and thus has access to
kernel APIs in the global environment, from code nested
within function bodies, which might run in response to user
code that has poisoned the global environment. If uCall is
used in the top-level, we label the return value as k, meaning
it can be used to load kernel APIs. However, the above rule
is for inner-level expressions so we cannot trust that the
result has not been hijacked: the return type is labeled u.
Dynamic eld sets: The second rule applies to the syntactic
form o[i] = v. Intuitively, if i is not a direct eld of o, os
prototype chain will be checked for i, which might resolve
to a eld on Object.prototype. In the case of poisoning
with a setter, similar to attack 4 (Section IV-A), o may leak.
As we do not statically know the value of i, such a call is
only allowed if os type has a privilege label that states it is
acceptable to leak it to user code (L
1
u).
487
Authorized licensed use limited to: Jaypee Institute of Technology. Downloaded on July 22,2010 at 07:16:10 UTC from IEEE Xplore. Restrictions apply.
1) K =
k
2) U =
u
3) {. . . , fldn : Tn} = (. . . ; fldn : Tn ref
label(Tn)
)
o
4) . . . x Tn To = . . . Tn
o
To
where label(T
L
) = L.
Figure 8: Interpretation of policy annotations as type annotations.
o : T
L
1
1
i : T
L
2
2
v : T
L
3
3
L
1
, L
2
, L
3
u
o[i] = v : T
L3
3
(dyn set)
If term i is an object, it will be dispatched to the toString
method. toString might be poisoned to leak object i, so
we must check that is label allows it to ow to user values
(L
2
u). Due to these same attacks, we must also ensure
that it is acceptable to leak v to user code: L
3
u. The other
antecedents simply check that the terms are well-typed.
Static eld sets with records. The third rule applies to form
o.f = v where o is dened within the policy code, such as
if we wanted to modify the whitelist. In this case, o must
be a record type (with policy origin):
o : (f : T
L
; r)
o
v : T
L
o.f = v : T
L
(k stat set)
Unlike with dynamic eld sets, we can check that the desired
eld actually exists in the record, in which case there is no
prototype poisoning attack to leak o. If the records eld
and assignments right-hand side labels and types match,
the assigned value will not be leaked either.
Label Inference. Label inference follows base type infer-
ence. If labels are ignored, the base types may be inferred
using ML-style unication. Concrete label o is introduced
for type constructors and labels k and u for top-level
and inner-level global variables, respectively. The remaining
labels are variables that may be inferred as as suggested in
the JQual project, for instance [18] for general type qualier
labels.
V. POLICIES
In this section we present a variety of ne-grained policies
we expressed with CONSCRIPT. To collect these policies, we
studied bugs and anti-patterns in both raw JavaScript as
well as popular JavaScript libraries such as jQuery. We also
investigated and rewrote some of the policies published in
the literature [2, 3] in CONSCRIPT. We discovered that in
some cases, a few lines of policy code can replace a new
specialized HTML tag. This demonstrates that CONSCRIPT
provides a general enforcement mechanism for a wide range
of application-level security policies. Crucially, our type
system helped us avoid many errors found in previously
proposed policies and even a few of our own.
To help demonstrate the value our type system described
in Section IV-C provides, we manually annotate variable
declarations and function parameters with security labels.
Due to some invariants of CONSCRIPTs use of labeled
types, our policy annotations (Section V) use a simpler
language than that of our type annotations . Figure 8 denes
a syntax-directed translation from policy annotations to more
verbose but canonical labeled type annotations. The intuition
is that terms with label u or k have base type (rules 1
and 2, exercised in policy 2) and that terms whose base types
are constructors will have label o (rules 3 and 4, exercised
in policies 2 and 4, respectively). As these redundancies
may be reconstructed in a simple, direct manner, our policy
annotation language elides them.
In the remainder of this section, the policies are grouped
as controls on vectors for dynamic code introduction (Sec-
tion V-A), communication restrictions (Section V-B), doc-
ument object policies (Section V-C), and API and library
reliability guidelines (Section V-D).
A. Script Introduction Policies
We start with an important class of policies used for
controlled dynamic introduction of code. Recall that CON-
SCRIPT is designed to protect the hosting page from either
malicious or poorly-written third-party code and libraries.
As such, the hosting page may choose to enforce properties
of the introduced code and this section explores some of
these possibilities.
As an extreme, one might write a CONSCRIPT policy to
parse dynamically injected code and perform static analysis
on it, rejecting everything that does not match a static analy-
sis policy [11, 12]. Static analysis techniques currently strug-
gle with mechanisms for intercepting dynamically injected
code [12, 20], which CONSCRIPT more cleanly exposes, as
show below. Recall that in the case of script interception
advice, the policy is designed to return the code that the
JavaScript interpreter will proceed to run instead of the code
being introduced.
1. No dynamic scripts
The simplest policy is to simply disallow any code from being
introduced after a certain point, such as after the main library loads.
We encode disabling scripts by returning the empty string back to
the JavaScript interpreter.
<script src="main.js" policy="
aroundScript(function () { return ; }); "/>
2. No string arguments to setInterval, setTimeout
The functions setInterval and setTimeout run callbacks in
response to the passing of time. A closure is typically passed in
for the callback parameter. Surprisingly, and even commonly pro-
scribed in introductory tutorials, string arguments to be evaluated
may also be accepted. This attack vector may be easily dealt with.
let onlyFnc : K x U x U -> K =
function (setWhen : K, fn : U, time : U) {
if ((typeof fn) != "function") {
curse();
throw "The time API requires functions as inputs.";
} else {
return setWhen(fn, time);
}
};
488
Authorized licensed use limited to: Jaypee Institute of Technology. Downloaded on July 22,2010 at 07:16:10 UTC from IEEE Xplore. Restrictions apply.
around(setInterval, onlyFnc);
around(setTimeout, onlyFnc);
3. No inline scripts
Previous code injection attacks such as the Samy worm would often
try to attach malicious script to DOM elements. The policy below
aims to prevent inline scripts: if a scripts context is not the global
object, it is an inline script, so the empty string is returned to the
interpreter.
let glbl : K = this;
aroundScript(function (src) {
return glbl == this ? src : ""; });
4. Script tag whitelist
We can ensure that statically loaded script tags have a source listed
in whitelist w. When the advice function is invoked, the script
tag has been created, but the script has not yet been executed.
Therefore, for statically loaded scripts, checking the src attribute
of the last one in the document tree sufces. A more direct interface
would be to modify our system to also pass in the node or script
context as a parameter to the script advice function [6]. Issues of
correctness pertaining to whitelist use are covered in Section IV-B.
let glbl : K = this;
let getScripts : K = document.getElementsByTagName;
let doc : K = document;
let w : {"good.js": K} = {"good.js": true};
aroundScript(function (load : K, src : U) {
if (this == glbl) {
let scripts : U = uCall(doc, getScripts, "script");
return hasProp(w, scripts[scripts.length - 1].src) ?
load(src) : "";
} });
Note that we do not check the two eld accesses when looking
up the script src: getter functions might be invoked at these points,
arguably violating access path integrity (but not reference isola-
tion). We could statically check for getter and setter equivalents of
uCall at these points, but found such a restriction to be of little
benet.
5. NOINLINESCRIPT tag
BEEP [4] advocates the introduction of a <noscript> tag.
Fortunately, CONSCRIPT is general enough to implement this tag
in the form of a policy. As a ner-grained version, the following
policy prevents inline scripts from being loaded as descendants of
a <noinlinescript> tag:
let glbl : K = this;
let getScripts : K = document.getElementsByTagName;
let doc : K = document;
aroundScript(function (load : K, src : U) {
if (this == glbl) return src;
else {
let n : U = this;
while (n)
if (n.tagName == "NOINLINESCRIPT") return "";
else n = n.parentNode;
return src; } });
The signicance of this example is that we can securely
previously proposed HTML tags using our primitives, sep-
arating the slow process of dening new standards and
upgrading browsers from securing applications.
B. Communication Restrictions
Our trust model, reecting modern application design,
expands an applications trust boundary to include the client.
By trusting client-side computations, Web applications are
now sensitive to how a client communicates with untrusted
principals. Developers should now, for example, more care-
fully restrict how messages are passed to frames belonging to
untrusted origins or what RPC calls are made to third-party
servers. Browser policies are coarse and may be ignored; we
show how applications may enforce ne-grained policies on
communication.
6. Restrict XMLHttpRequest to secure connections
XMLHttpRequest enables communication with an
applications server without reloading a page. An instance
of the XMLHttpRequest object provides the method
open(mode, url, sync, username, password), where the
last two parameters are optional. A program that species a
username and password has heightened security concerns. The
following policy ensures, if a username and password is supplied,
that the connection is over HTTPS.
let substr : K = String.prototype.substr;
around((new XMLHttpRequest()).open,
function (o : K, m : U, u : U, a : U, nm : U, pw: U)
{
let name : K = toPrimitive(nm);
let password : K = toPrimitive(pw);
let url : K = toPrimitive(u);
if ((name || password)
&& uCall(url, substr, 0, 8) != "https://") {
curse(); throw "Use HTTPS for secure a XHR.";
} else
return uCall(this, o, m, url, a, name, password);
});
7. HTTP-only cookies
Servers often store state on the client to avoid costs associated with
maintaining session state between calls to the server. Cookies may
therefore contain valuable state information that should only be
read and written by the server. We therefore might want to disable
JavaScript access to cookies.
let httpOnly : K -> K = function (_ : K) {
curse(); throw "HTTP-only cookies"; };
around(getField(document, "cookie"), httpOnly);
around(setField(document, "cookie"), httpOnly);
8. Whitelist cross-frame messages
The postMessage function may transmit primitive values between
frames of differing origins. While a developer may specify the
intended origin of the receiving frame during a particular call,
which prevents man-in-the-middle attacks [21], the developer is
not obligated to. The following requires such a specication and,
further, limits communication to a whitelist of URIs.
let okOrigins : {"http://www.google.com": K}
= {"http://www.google.com": true};
around(window.postMessage,
function (p : K, msg : U, target : U) {
let t : K = toPrimitive(target);
if (!hasProp(okOrigins, t)) {
curse(); throw err;
} else return p(msg, t); });
9. Whitelist cross-domain requests
The push to have more application functionality run in the browser
has led to new primitives like XDomainRequest for communicating
with foreign servers without requiring a server-side proxy (which
might have performed its own access checks). Similar to the
489
Authorized licensed use limited to: Jaypee Institute of Technology. Downloaded on July 22,2010 at 07:16:10 UTC from IEEE Xplore. Restrictions apply.
postMessage example, we introduce a check against a whitelist
of URIs before allowing cross-domain server requests.
let w : {"http://www.google.com": K}
= {"http://www.google.com": true};
around((new XDomainRequest()).open),
function (x : K, a1 : U, url : U) {
let u : K = toPrimitive(url);
if (!hasProp(w, u)) {
curse(); throw err;
} else return x(a1, u); });
A subtlety of the XMLHttpRequest and XDomainRequest
examples are that we advise the function attached as method
open on request object instances. Each request object
calls the same function, one for XMLHttpRequest calls
and a different one for XDomainRequest calls. Using the
rqst.open(...) form just passes in rqst to the advised
function as the this object; despite advising a function
reached through one instance of a request object, we are
indeed advising the function shared by all of them. This is
analogous to advising eval by using just one alias.
C. DOM Interactions
DOM interaction are a common source of security aws.
This section shows how CONSCRIPT policies can help reign
in some of these issues.
10. No foreign links after a cookie access
The following policy, proposed by Kikuchi et al. [2], is intended
to prevent links from being used for cookie access. The rst
advice function represents eliminating side-channels. The second
advice function, after being triggered, enables a stricter policy
mode. The third advice function attaches a policy to src attributes
of dynamically generated nodes: it avoids toString rewriting
attacks and, whenever the strict policy is enabled, whitelists target
domains.
around(document.setAttribute, function () {
curse(); throw err; });
let ok : K = true;
around(getFld("cookie", document), function (g : K) {
ok = false;
return g(); });
let slice : K = Array.prototype.slice;
around(document.createElement, function (c : K, t : U) {
let elt : U = uCall(document, c, t);
if (elt.nodeName == "A")
around(setFld("href", elt),
function (setter : K, v : U) {
let str : K = toPrimitive(v);
if (ok ||
uCall(str, slice, 12) == "http://g.com/"))
setter(str);
else {
curse();
throw err; } });
return elt;
});
We show how this policy can be implemented in CON-
SCRIPT with only a few lines of policy code.
11. Limit popup window construction
Below we show the implementation of another policy proposed by
Kikuchi et al. [2], we can limit the number of attempts to open a
popup window by counting the number of invocations. Further, we
can restrict the dimensions of the popup window.
let split : K = String.prototype.split;
let toLower : K = String.prototype.toLowerCase();
let match : K = String.prototype.match;
let toInt : K = parseInt;
let count : K = 0;
around(window.open,
function (w : K, url : U, name : U, features : U) {
if (count++ > 2) {
curse(); throw err;
} else if (features) {
let f = toPrimitive(features);
let a = uCall(f, split, ",");
let i = 0;
while (i < a.length) {
var o = uCall(a[i], split, "=");
var prop = uCall(o[0], toLower);
if (uCall(prop, match, "width|height"))
if (toInt(o[1]) < 100) {
curse(); throw err; }
i++; }
return w(url, name, f); } });
To further prevent click-jacking, a similar policy might also
be used to restrict where the window may be moved.
12. Disable dynamic IFRAME creation
Phung et al. [3] introduce a policy to prevent the construction of
IFRAME elements using createElement. Note that unlike the
original policy, ours is safe from attacks like running delete on
the attribute or accessing the createElement function from other
aliases.
around(document.createElement,
function (c : K, tag : U) {
let elt : U = uCall(document, c, tag);
if (elt.nodeName == "IFRAME") throw err;
else return elt; });
13. Whitelist URL redirections
Phung et al. [3] advocate checking programmatic URL redirections
against a whitelist. Note in the following policy the common theme
of not leaking the whitelist:
let whitelist : {"http://microsoft.com": K}
= {"http://microsoft.com": true};
around(setFld(document, "location"),
function (setter : K, url : U) {
let to : K = toPrimitive(url);
if (hasProp(whitelist, to)) setter(to);
else { curse(); throw err; } });
14. Prevent resource abuse
A common policy is for preventing abuse of resources like modal
dialogs. These may be disabled simply:
let err : K -> K = function () { curse(); throw err; });
around(prompt, err); around(alert, err);
D. API and Programming Reliability Guidelines
A key use case for advice is to introduce additional
constraints such as pre- and post-conditions on the use
of important APIs. In the following examples, also note
how the structured nature of advice allows us to install
upgrades to third-party libraries like jQuery without needing
to manually reinstrument or otherwise specially handle the
new versions in our policies.
15. Simple and fast jQuery selectors
$ is a core operator in the popular jQuery library that, given
a selector expression, returns the matching document elements.
490
Authorized licensed use limited to: Jaypee Institute of Technology. Downloaded on July 22,2010 at 07:16:10 UTC from IEEE Xplore. Restrictions apply.
For code style or, more commonly, performance concerns about
selectors, a simple pre-condition is to disallow selectors with slow
composition operators.
<script src="jQuery.js" policy="
let match : K = String.prototype.match;
let r : K = /^[a-zA-Z0-9.#:]+(( > | )[a-zA-Z0-9.#:]+)+$/;
around($, function ($ : K, selStr : U) {
let s : K = toPrimitive(selStr);
if (!uCall(s, match, r)) {
curse();
throw Compose selectors only with ( > ) or ( ).;
} else return $(s); });"/>
16. Explicit jQuery selector failure
An anti-pattern by jQuery is to silently fail when no elements are
returned by $, allowing a library user to attach behavior to the
null-set. An application may choose to add the post-condition that
$ return values should not be empty.
<script src="jQuery.js" policy="
around($, function ($ : K, expr : U, ctx : U) {
let nodes : U = $(expr, ctx);
if (!nodes.length) throw Nothing was selected.;
else return nodes; }); "/>
17. Staged eval restrictions
A common implicit invariant in JavaScript applications is that
they use eval [22] but only in restricted ways. This might more
precisely appear as a staged precondition. For example, we might
allow the trusted jQuery library to initialize itself using eval but,
for all subsequent code, we might then restrict usage of eval to
deserializing JSON objects.
<script src="jQuery.js" policy="
let parse : K = JSON.parse;
around(eval : K, function (_ : K, evalStrArg : U) {
curse();
return parse(evalStrArg); }); }); "/>
VI. AUTOMATICALLY GENERATED POLICIES
Writing policies by hand places the burden on the devel-
oper to get things right. Fortunately, relatively few modern
large-scale Web applications are constructed in isolation,
without using a framework or a toolkit of some kind, such
as GWT [23], Volta [24], Java J2EE, ASP.NET, etc. These
frameworks can bring in policies of their own that extend
to applications written on top of them. Policies specic to
a particular application can also be inferred through static
analysis or runtime training. In this section we explore two
case studies in generating and then enforcing such policies.
The rst described in Section VI-A uses a very simple form
of static analysis on the server to restrict possible behavior
on the client. The second described in Section VI-B uses
runtime training to determine expected benign behavior
and then rejects behaviors outside of the training set.
Once a policy is generated, it must be correctly and
efciently enforced. We demonstrate CONSCRIPT can en-
force our generated policies, and, in Section VII, assess
performance.
A. Private Methods in Script#
Script# is a tool that translates C# code into
JavaScript [25]. This tool is used in a variety of large-
scale commercial projects such as Live Maps to simplify
and quicken the development process. As part of its C#-
to-JavaScript translation, Script# takes a set of C# classes
and translates them into JavaScript. However, these two
languages are really quite different. One area of distinction
is that C# supports access qualiers such as internal,
private, protected, and public, and JavaScript does
not. After the translation takes place, a previously private
method is effectively accessible as a public one to any
piece of code that is loaded before and after the code that
has been translated with Script#. This issue is sometimes
referred to as failure of full abstraction [26], and leads to
unauthorized code and data access.
Fortunately, CONSCRIPT makes this deciency simple to
rectify by generating a policy as part of the translation
process. We traverse the original C# program source ofine,
identifying private methods and, for each, also identity
public entry points to the classes (public methods) in which
the private methods are found. Note that this information is
readily available to a Script# language compiler.
We automatically generate policies from this list: an
enabled status bit is allocated for every class, where entry
through a public point is modied to enable the corre-
sponding class bit, exit resets it, and access of a private
method checks it. The privileged policy bits are encapsulated
within the set of policies and the (anonymous) policies are
associated with the method objects; private methods may
only be called when public ones are on the stack, akin to
cow pointcuts in other aspect systems [15]. If we exposed
arguments.caller to policies, we could match the exact
access modier semantics and would only need to instrument
the private methods.
B. Intrusion Detection of Client-Side Exploits
In practice, many JavaScript applications only exercise a
small subset of browser capabilities, but this subset varies
between applications. According to the principle of least
authority, if an application does not need a capability, it
should not have it. Instead of using a preset list, which
may be too lax, or manually generating the policy list of
acceptable functionality, which may be error-prone, here
we demonstrate the potential for automatically restricting
browser functionality to a subset. Such a subset can be
synthesized through runtime training. This is similar to intru-
sion detection techniques that train on valid runs observing
system calls or their sequences, proceeding to ag all other
possibilities as suspicious [20, 27, 28]. An interesting obser-
vation is that CONSCRIPT may be used to apply logging
aspects to a large number of functions to see which ones
are used at the time of training. CONSCRIPT can also be
used to enforce the blacklist at the time of detection.
491
Authorized licensed use limited to: Jaypee Institute of Technology. Downloaded on July 22,2010 at 07:16:10 UTC from IEEE Xplore. Restrictions apply.
This general approach may be used to harden many
Web sites and applications. Consider the popular Web ap-
plications GMail and Google Calendar. As a Web-based
program designed to display untrusted HTML email, GMail
is a particularly good example for this style of intrusion
detection. If a maliciously crafted message breaks out of
GMail sanitization, which is what happened in the case of
the Yamanner worm [29], our aspects will ag attempts
to execute previously unseen dangerous method calls. A
Google Calendar user might similarly attempt to circumvent
sanitization by creating a meeting request with a malicious
body and sending it to others.
In our experiments, we blacklisted XDomainRequest,
XMLHttpRequest, postMessage, setTimeout,
setInterval, eval, alert, prompt and several other
potentially dangerous methods not seen during training. We
did not encounter any intrusion detection alarms.
VII. EVALUATION
This section presents an evaluation of CONSCRIPT in the
context of Internet Explorer 8. Our primary focus is on
the runtime overhead introduced with CONSCRIPT instru-
mentation compared to alternative techniques. Section VII-A
talks about our experimental setup. Section VII-B evaluates
micro-benchmarks and Section VII-C focuses on applying
CONSCRIPT advice to large AJAX sites and applications
such as MSN, GMail, and Live Desktop; a summary of
information for these applications is given in Figure 10. All
measurements reported in this section were performed on
a Dual Core 3GHz Pentium 2 machine running Windows
Vista. In addition to measuring the performance overhead,
we also compare CONSCRIPTs space overhead to that
induced by JavaScript code rewriting systems Caja [7]
and WebSandbox [8] and the advice system proposed in
Kikuchi et al. [2] in Section VII-D.
A. Browser Modications for CONSCRIPT
As explained in Section III, we modied the JavaScript
interpreter in Internet Explorer 8 to support advising func-
tions and dynamic script introduction. In addition, for
the integrity of policies, we had to disable features like
arguments.callee, as suggested by ECMAScript 5 [16],
and introduce more secure calling forms for primitive func-
tions like around, uCall, etc., as discussed in Section IV-B.
Overall, our changes are small and we believe similar
augmentations can be made to scripting engines of other
browsers. In total, we have added 969 lines to the JavaScript
interpreter over 60 different code locations, which consti-
tutes a small fraction of the overall interpreter size. About
half of these changes were boilerplate for exposing new
functionality as JavaScript functions: once discounted, the
average instrumentation point was only 8 lines of code. In
contrast, Caja [7], a source rewriting tool, currently has
over 181,000 lines of code in its main source directory.
Task r
a
w
w
r
a
p
p
i
n
g
b
l
e
s
s
i
n
g
a
u
t
o
-
b
l
e
s
s
i
n
g
USER-DEFINED FUNCTIONS
function(){} 1 3.86 1.06 1.02
function(){return + 1; } 1 4.04 1.07 1.03
NATIVE FUNCTIONS
Math.tan(5) 1 1.37 2.16 1.27
eval(1) 1 1.53 1.47 1.36
eval(if(true)true; false; ) 1 2.93 1.79 1.72
FOREIGN FUNCTIONS
getElementsByTagName(div) 1 5.57 1.31 1.20
createElement(div) 1 4.63 1.2 1.10
Average 1 3.42 1.44 1.24
Figure 9: Runtime overhead of applying aspects to micro-benchmarks.
Our modications are not veried, but verifying even the
uninstrumented interpreter is an open problem, and our
approach assuages concerns about browser-specic logic and
library-level reimplementation of core functionality.
B. Runtime Overhead on Micro-benchmarks
Potentially thwarting our goal of ne-grained policy sup-
port is interpositioning cost. Language-level support, in
static languages, has been shown to take away much of
the instrumentation cost of an aspect system. In particular,
the cost of additional function dispatches introduced by a
nave syntactic desugaring of an aspect might be eliminated
by approaches like inlining. We nd similar benets for a
dynamic language. In this section we study the overhead
of 1) mediating a function call with advice, and 2) of lesser
concern, the initialization overhead of associating an advice
policy with a function to protect.
Overhead of Advice Interpositioning. We consider the cost
of running advice that simply proxies calls with no side-
effect beyond the seemingly inherent performance cost of an
indirected call. This removes the policy cost, leaving only the
advice mechanism and the original function. Further rening
previous benchmarks of a proposed wrapping system [3], we
distinguish between advising user dened functions, native
functions provided by the JavaScript interpreter (at low cost),
and external native DOM functions exposed to the JavaScript
interpreter through a COM interface (at a high cost). A
summary of our micro-measurements is shown in Figure 9.
To collect out measurements, for every benchmark, we
start a new JavaScript runtime, run 10,000 invocations
of the advised function, and normalize over the cost of
running 10,000 invocations of the function unadvised.
We also measure the overhead of the wrapping approach
discussed earlier. Our measured performance of wrapper-
based advice is 23x better than reported by others [3],
perhaps due to using a different browser or our care in
492
Authorized licensed use limited to: Jaypee Institute of Technology. Downloaded on July 22,2010 at 07:16:10 UTC from IEEE Xplore. Restrictions apply.
JavaScript
Application URL les size (KB)
GMail mail.google.com 32 421
Google Calendar calendar.google.com 5 360
Live Desktop www.mesh.com 3 178
MSN www.msn.com 3 17
Figure 10: Macro-benchmark information summary.
not inserting extraneous calls nor conating policy logic
with advice mechanisms. In almost all benchmarks, even
nave language-level support of advice with explicit bless
calls (column bless) performs 2.7x faster than wrapping
(column wrapping). Introducing further optimizations, like
auto-blessing (column auto-bless), always outperforms
wrapping with an average 2.9x speedup over wrapped invo-
cation speed. While the benets of language-based support
were largely expected for user-dened functions (rows 12),
speedup in advising native interpreter functions (tests 35)
and DOM functions (tests 67), which are often privileged,
is not as obvious.
Initialization Overhead. A survey of aspect literature shows
that advice registration can be quite expensive: an unopti-
mized DOM wrapper approach takes 9 ms to initialize [30]
and therefore can be as expensive as 100 ms on a mobile
device [31].
In CONSCRIPT, starting a new application session creates
a new interpreter session with globally available advice func-
tions. A new local environment is created that aliases these
advice function objects and global references to them are
deleted, making the local environment privileged. Note that
these manipulations only pertain to generally small advice
functions, not the large set of DOM and JavaScript library
functions that would be necessary for complete mediation
in other approaches. Policies are then run, not in the global
environment, but the privileged local one.
The initialization overhead is quite small in our ex-
periments. Based on a trial of 10,000 runs, creating the
privileged environment and removing global access costs
only 24 s. The remaining costs for loading policies are
analogous to the optimized process of handling source
attributes for a <SCRIPT> tag.
C. Runtime Overhead on Macro-benchmarks
While the experiments on micro-benchmarks above show
superiority of CONSCRIPT compared to other techniques,
the real test of our system is when it comes to advising
large existing applications. To this end, we automatically
generate policies, as discussed in Section VI, and apply them
to large, JavaScript-heavy sites and applications such as
MSN, Google Maps, and Google Calendar, etc. to measure
the performance overhead in normal use.
For every experiment, we locally cached all resource
requests and performed dynamic rewriting of Web pages
to add our advice to the <HEAD> section using the Fid-
dler proxy [32]. For performance measurements of large
7
1
30
73
63
0
10
20
30
40
30
60
70
80
90
100
Coogle Maps (183ms) MSn (439ms) CMall (736ms)
k
u
n
t
|
m
e
o
v
e
r
h
e
a
d
ConScrlpL uoCoMo (!avaScrlpL rewrlLlng)
Figure 11: Macro-benchmarks: enforcing policies in Section VI-B using
CONSCRIPT has low overhead, compared to rewriting techniques.
highly interactive Web applications, deciding how to mea-
sure the overhead presents a difculty. Our strategy has
been to nd two runtime events that do not exhibit much
runtime variance such as the onload event and the rst
XmlHttpRequest being issued. Our measured slowdowns
are thus mostly of CPU time; slowdown in a network-
bound interactions like page loading is likely less than our
reported benchmarks. This approach for experimenting with
third-party sites was previously advocated in the AjaxScope
project [33].
Overhead of Private Methods in Script# Policy. For the
policy in Section VI-A, our protection of Script# private
methods exhibits two kinds of runtime costs: instantiation
overhead during application loading and then runtime moni-
toring overhead. Of concern, to protect a private method, all
public entry points in the same class are also instrumented.
This is unlike our other policies as the cost may be linear
in the program size.
For this experiment, we applied the policy to the Live
Desktop application that is part of the application suite
located at www.mesh.com. We instrumented two core le
and folder manipulation class les of the Live Desktop
shared desktop application to evaluate these overheads,
spanning 5% of the main library (23 private methods
and 32 public ones out of 1,327 total functions). We have
only automated policy generation given the namespace in-
formation: while the C# compiler generates this information,
we manually extracted it for our benchmark. We averaged
our overhead numbers over 20 trials, with most network
resources cached locally.
There is no statistically signicant impact on loading
the application when measured from beginning to end (and
forcing caching). The entire set of 55 method policies was
installed in 1 ms or less our JavaScript timer does not
provide ner granularity representing at most 0.3% of the
processing time (and our micro-benchmarks suggest much
less). For the task of opening a folder, 2 instrumented private
calls are made, with 40 invocations of other methods in the
same classes, accounting for 1.4% of the calls. We detected
no statistically signicant overhead: the average 0.9% slow-
493
Authorized licensed use limited to: Jaypee Institute of Technology. Downloaded on July 22,2010 at 07:16:10 UTC from IEEE Xplore. Restrictions apply.
1.0
1.7
4.8
1.3
1.0
1.3
3.9
10.4
1.0
1.3
4.4
1.3
0
1
2
3
4
3
6
7
8
9
10
11
ConScrlpL uocomo Ca[a Sandbox
S
p
a
c
e
b
|
o
w
-
u
p
b
e
c
a
u
s
e
o
f
a
d
v
|
c
e
c
o
d
e
MSn CMall Coogle Maps
Figure 12: Code size increase for different instrumentation technologies.
down is below the 3.5% range of experimental error.
Overhead of Intrusion Detection Policy. For the intrusion
detection policy in Section VI-B, to perform our experi-
ments, we created a representative list of 15 common attack
vectors. For example, postMessage and XDomainRequest
can be used to circumvent the single origin policy and
functions are typically coded without considering the pos-
sibility of defineProperty changing the behavior of eld
access. Next, we monitored scripts sent to a browser from
the server, checking against a master list of privileged DOM
functions. Whatever did not occur was added to the nal
blacklist. As we cannot directly access the code of third-
party sites, we used Fiddler to rewrite pages received by
our test browser to load our blacklist advice, mimicking our
suggested deployment approach.
We report the performance impact as part of our overall
performance analysis, as shown in Figure 11. We ran 30
trials of uninstrumented and instrumented versions. We
compare measured slowdown to that reported for JavaScript
rewriting overhead [2], though, unfortunately, error infor-
mation is unavailable. Fundamentally, when blacklisting
functions under benign scenarios, the only cost is in instru-
menting blacklist functions at initialization time. For most
applications we tested (including Google Calendar, which is
not shown), the standard deviation of the slowdown was 5%,
with the average slowdown being negligible (0%). While
we show an average 7% overhead on Google Maps, as its
slowdown deviation is 46%, the slowdown is not statistically
signicant. Note that we have not observed any intrusion
detection alarms while testing these applications.
D. Code Size Increase
JavaScript code size is a major concern for Web appli-
cation performance [34], which becomes especially acute
for mobile devices with limited storage capacity and for
Web applications in general where resources are transferred
over the network. Our timing benchmark measurements
were performed on locally cached les. However, we must
consider the le size increases related to verbose policies
and rewriting, as initial network transfer time is crucial to
fast application loading.
Figure 12 shows that our advice system has small and
constant space overhead relative to other approaches, which,
in contrast, have a cost linear in the size of application.
We compare CONSCRIPT with the size blowup of running
Docomo [2]
4
, Caja [7], and WebSandbox [8].
We selected JavaScript les from MSN, GMail, and
Google Maps and ran them through existing rewriting
tools [7, 8], or used previously reported results when no
tool was available [2]. Reecting best practices, we then
run both the input and output through a suite of JavaScript
compressors and pick the smallest le size.
For all, we compare the initial le size to the size of the
secured one. Our policies add an average 0.7 KB to the
compressed le size. As applications grow in size, relative
cost decreases because the policy size is constant in most of
our examples. In contrast, variable in the source rewriter and
the application, a cost linear in the source size was incurred.
We show the average linear cost per rewriter; we suspect the
importance of considering the application is that different
source generation tools (e.g., miniers or tier-splitters) were
used on a per-application basis.
VIII. RELATED WORK
We implement much of the vision previously proposed
by Erlingsson and Livshits [6] and examine the unaddressed
problem of writing secure programmatic policies. There have
been signicant advances since the original proposal:
Static analysis. Policies might be phrased as properties
to be statically veried. On benchmarks for a control-ow
analysis, Guha et al. found large JavaScript applications need
context sensitivity prohibitively higher than that for appli-
cations written in more static languages [20]. Evaluating
a points-to analysis, Guarnieri et al. [11] found JavaScript
widgets (that are typically between 50-250 lines) utilize a
more tractable language subset. It is still unclear, however,
how to apply such a static analysis to large, expressive Web
applications.
Type systems. Our type system in Section IV-C provides
a form of fully-static checking and considers the subtleties
of JavaScript, unlike Chughs [12]. It is derived from label-
based information ow type systems like Myers [17] and
Pottiers [35]. Non-interference was too strict of a property
for our domain: we must simply prevent references to policy
heap objects from leaking. Inference is well-studied for such
systems; further aiding usability, due to our safety properties
and interpreter modications, we only require policy code
to pass the checker.
Browser tags. There are several proposals for modifying
browsers to support coarse tag-based policies. For example,
BEEP [4] introduces both a <noscript> tag to disallow
scripts in descendant nodes and an application meta-tag for
hash-based whitelisting of dynamically loaded scripts. Our
4
The measurements of Kikuchi et al. [2] are copied from the reported
ones as there was no public way to reproduce them.
494
Authorized licensed use limited to: Jaypee Institute of Technology. Downloaded on July 22,2010 at 07:16:10 UTC from IEEE Xplore. Restrictions apply.
more general script pointcuts enable encoding these primi-
tives by supporting context-sensitive advice at the point in
which a script enters the interpreter. MashupOS [5] proposes
open and closed sandbox tags. These enable an application
to load a script and manipulate the scripts content while
preventing the script from manipulating the application.
Section V lists examples of CONSCRIPT policies that largely
obviate the need for specialized tags.
Isolation languages. ADSafe [14], FBJS [36], Caja [7],
and WebSandbox [8] are JavaScript variants designed to run
untrusted gadgets in isolation from the rest of a page without
modifying browsers. ADSafe syntactically checks that a
gadget does not use many JavaScript language features such
as the this object; this is analogous to our heavily restricted
policy language subset except the entire program must be
written in it. The rest support larger JavaScript subsets by
rewriting gadget source to perform dynamic checks and
lookup translations. However, implementation correctness
of these systems has been questioned in the past [37]. By
instrumenting the browser instead, it is possible to get much
better assurances of enforcement correctness.
Shallow wrapping. Instead of the pervasively wrapping and
rewriting, an option is to only advise particular method
calls [3, 40] by dynamically reassigning an objects method
to point to a wrapped, instrumented verison. While this may
be acceptable for some use cases like debugging [3] that
tolerate error, it is inappropriate for securing large APIs.
For example, there are many aliases to the function eval
that must be manually enumerated, and, unlike the rewriting
and deep wrapping systems, there are no controls against
inadvertant escaping of aliases. As a result, we found these
systems to be susceptible to our policy integrity attacks.
Weaving aspects into source code. A traditional technique
for implementing aspects that solves the above aliasing prob-
lem is, instead of forcing the developer to rewrite all aliases
to a function, to just rewrite the function. Kikuchi et al. [2]
and Washizaki et al. [41] demonstrate this idea for JavaScript
by introducing a serverside proxy to rewrite outgoing pages.
Unfortunately, the server cost is not negligible. Furthermore,
JavaScript is dynamic: traditional aspect weavers consume
type-based pointcuts, which is too imprecise for JavaScript.
Using references for ner pointcuts currently requires perva-
sive rewriting to pinpoint enforcement locations at runtime.
Next, the DOM API contains many privileged functions:
there is no source code available to rewrite. We avoid these
problems by instrumenting the interpreter.
Aspect interfaces for dynamic languages. How aspects are
exposed to developers is crucial. In JavaScript, pointcuts are
too imprecise if specied with type signatures. We do not
grant ambient authority to aspects [39]: instead of accepting
a variable or function name as a pointcut as Washizaki et
al. do [41], we advocate requiring a reference to a function
in order to be allowed to advise it. Kikuchi et al. [2] sug-
gest developers control JavaScript applications using a new
XML-based language with code template and state machine
tags. In contrast, we propose the single succinct construct
around. This construct in conjunction with libraries may be
used to develop other forms of advice (before, etc.) and to
provide pointcut combinators.
Secure aspects. While a traditional use case for aspects has
been for enforcing cross-cutting security (safety) properties,
discussion of securing aspect systems at the language level is
more recent. Dantas et al. [42] explore how to provide a non-
interference property: a program may not be behaviorally
modied by a malicious aspect. We weaken this property to
abide by the object capability model: advice may only apply
to a function given a reference to the function.
We primarily focus on an opposite threat model: aspects
should be protected from subsequent code. Systems like
Naccio [43] and SASI [44] provide instrumentation analo-
gous to ours for preserving encapsulation (Section IV-B) but
do not support policies that interact with non-policy code. In
contrast, for example, our verier may check that a policys
interactions with the DOM do not leak a privileged whitelist
object (Section IV-C).
IX. CONCLUSIONS
This paper presents CONSCRIPT, a system that imple-
ments client-side deep advice for security. CONSCRIPT has
been implemented by extending the Internet Explorer 8
JavaScript engine. To demonstrate the expressive power
of CONSCRIPT, we presented 17 security and reliability
policies that are specic to an application and are drawn
from literature, practice, and analysis. We applied a type
system to these policies to ensure that, once they type-
check, they are free from a range of common bugs that were
found in JavaScript policies before. We further presented two
strategies for automatically producing CONSCRIPT policies
through static and runtime analysis, demonstrating policies
need not be created by hand, and that CONSCRIPT provides
expressive primitives that simplify the implementation of
policy generation tools.
We conducted a range of experiments with CONSCRIPT,
both using micro-benchmarks and large, popular Web ap-
plications. In our extensive experiments, both the time and
space overhead of CONSCRIPT has been demonstrated to be
negligible for most large applications, hovering around 1%,
which is often orders of magnitude smaller than what had
been shown by previously published techniques.
REFERENCES
[1] B. Chess, Y. T. ONeil, and J. West, JavaScript hi-
jacking, www.fortifysoftware.com/servlet/downloads/public/
JavaScript Hijacking.pdf, Mar. 2007.
[2] H. Kikuchi, D. Yu, A. Chander, H. Inamura, and I. Serikov,
JavaScript instrumentation in practice, in Proceedings of the
Asian Symposium on Programming Languages and Systems,
2008.
495
Authorized licensed use limited to: Jaypee Institute of Technology. Downloaded on July 22,2010 at 07:16:10 UTC from IEEE Xplore. Restrictions apply.
[3] P. H. Phung, D. Sands, and A. Chudnov, Lightweight self-
protecting JavaScript, in Proceedings of the International
Symposium on Information, Computer, and Communications
Security, 2009.
[4] T. Jim, N. Swamy, and M. Hicks, Defeating script injection
attacks with browser-enforced embedded policies, in Pro-
ceedings of the International Conference on World Wide Web,
2007.
[5] J. Howell, C. Jackson, H. J. Wang, and X. Fan, Mashu-
pOS: Operating system abstractions for client mashups, in
Proceedings of the Workshop on Hot Topics in Operating
Systems, May 2007.
[6]
U. Erlingsson, B. Livshits, and Y. Xie, End-to-end Web
application security, in Proceedings of the Workshop on Hot
Topics in Operating Systems, May 2007.
[7] M. S. Miller, M. Samuel, B. Laurie, I. Awad, and M. Stay,
Caja - safe active content in sanitized JavaScript, Octo-
ber 2007, http://google-caja.googlecode.com/les/caja-spec-
2007-10-11.pdf.
[8] S. Isaacs and D. Manolescu, Web Sandbox - Microsoft Live
Labs, http://websandbox.livelabs.com/, 2009.
[9] C. Reis, J. Dunagan, H. Wang, O. Dubrovsky, and S. Esmeir,
BrowserShield: Vulnerability-driven ltering of dynamic
HTML, in Proceedings of the Operating System Design and
Implementation, 2006.
[10] T. Elrad, R. E. Filman, and A. Bader, Aspect-oriented
programming: Introduction, Communications of the ACM,
vol. 44, no. 10, 2001.
[11] S. Guarnieri and B. Livshits, Gatekeeper: Mostly static
enforcement of security and reliability policies for JavaScript
code, in Proceedings of the Usenix Security Symposium,
Aug. 2009.
[12] R. Chugh, J. A. Meister, R. Jhala, and S. Lerner, Staged in-
formation ow for JavaScript, in Proceedings of the Confer-
ence on Programming Language Design and Implementation,
2009.
[13] Mozilla Foundation, Using JavaScript code modules, Sep.
2009.
[14] D. Crockford, ADSafe, adsafe.org.
[15] G. Kiczales, E. Hilsdale, J. Hugunin, M. Kersten, J. Palm, and
W. G. Griswold, An overview of AspectJ, in Proceedings of
the European Conference on Object-Oriented Programming,
2001.
[16] ECMA International, ECMA-262: ECMAScript language
specication, version 3.1, Sep. 2009.
[17] A. C. Myers, JFlow: practical mostly-static information ow
control, in Proceedings of the Symposium on Principles of
Programming Languages, 1999.
[18] D. Greeneldboyce and J. S. Foster, Type qualier inference
for Java, SIGPLAN Notices, vol. 42, no. 10, 2007.
[19] B. Livshits and L. A. Meyerovich, ConScript: Specifying
and enforcing ne-grained security policies for JavaScript in
the browser, Microsoft Research, Tech. Rep. MSR-TR-2009-
158, Nov. 2009.
[20] A. Guha, S. Krishnamurthi, and T. Jim, Using static analysis
for AJAX intrusion detection, in Proceedings of the Interna-
tional Conference on World Wide Web, 2009.
[21] A. Barth, C. Jackson, and J. C. Mitchell, Securing frame
communication in browsers, in Proceedings of the Confer-
ence on Security Symposium, 2008.
[22] C. Yue and H. Wang, Characterizing insecure JavaScript
practices on the Web, in Proceedings of the International
Conference on World Wide Web, 2009.
[23] Google Web Toolkit, http://code.google.com/webtoolkit.
[24] Microsoft Corporation, Microsoft Live Labs Volta, http://
labs.live.com/volta/, 2007.
[25] N. Kothari, Script#, http://projects.nikhilk.net/ScriptSharp/,
2008.
[26] A. Kennedy, Securing the .NET programming model, The-
oretical Computer Science, vol. 364, no. 3, 2006.
[27] C. Warrender, S. Forrest, and B. Pearlmutter, Detecting
intrusions using system calls: Alternative data models, in
Proceedings of the IEEE Symposium on Security and Privacy,
vol. 0, 1999.
[28] E. Eskin, S. J. Stolfo, and W. Lee, Modeling system calls
for intrusion detection with dynamic window sizes, DARPA
Information Survivability Conference and Exposition,, vol. 1,
2001.
[29] The JS.Yamanner worm, http://www.f-secure.com/v-descs/
yamanner a.shtml, 2006.
[30] L. A. Meyerovich, A. P. Felt, and M. S. Miller, Object
views: Fine-grained sharing in browsers, in Proceedings of
the International Conference on World Wide Web, April 2010.
[31] C. G. Jones, R. Liu, L. Meyerovich, K. Asanovic, and
R. Bodk, Parallelizing the web browser, in Proceedings of
the Workshop on Hot Topics in Parallelism, March 2009.
[32] E. Lawrence, Fiddler: Web debugging proxy, http://www.
ddlertool.com/ddler/, 2007.
[33] E. Kcman and B. Livshits, AjaxScope: a platform for
remotely monitoring the client-side behavior of Web 2.0 ap-
plications, in Proceedings of ACM Symposium on Operating
Systems Principles, Oct. 2007.
[34] B. Livshits and E. Kcman, Doloto: Code splitting for
network-bound Web 2.0 applications, in Proceedings of the
International Symposium on the Foundations of Software
Engineering, Sep. 2008.
[35] F. Pottier and S. Conchon, Information ow inference for
free, SIGPLAN Notices, vol. 35, no. 9, 2000.
[36] Facebook, FBJS - Facebook Developer Wiki, July 2007,
http://wiki.developers.facebook.com/index.php/FBJS.
[37] M. Finifter, J. Weinberger, and A. Barth, Preventing capabil-
ity leaks in secure Javascript subsets, in Proceedings of the
Network and Distributed System Security Symposium, 2010.
[38] A. G. Guha, J. Matthews, R. B. Findler, and S. Krishnamurthi,
Relationally-parametric polymorphic contracts, in Proceed-
ings of the Symposium on Dynamic Languages, 2007.
[39] M. S. Miller, Robust composition: Towards a unied ap-
proach to access control and concurrency control, Ph.D.
dissertation, Johns Hopkins University, Baltimore, Maryland,
USA, May 2006.
[40] R. Porotnikov, AOP fun with JavaScript, July 2001,
http://www.jroller.com/deep/date/20030701.
[41] H. Washizaki, A. Kubo, T. Mizumachi, K. Eguchi,
Y. Fukazawa, N. Yoshioka, H. Kanuka, T. Kodaka, N. Sugi-
moto, Y. Nagai, and R. Yamamoto, AOJS: Aspect-oriented
JavaScript programming framework for Web development, in
Proceedings of the Workshop on Aspects, Components, and
Patterns for Infrastructure Software, 2009.
[42] D. S. Dantas and D. Walker, Harmless advice, in Pro-
ceedings of the Symposium on Principles of Programming
Languages, 2006.
[43] D. Evans and A. Twyman, Flexible policy-directed code
safety, in Proceedings of the IEEE Symposium on Security
and Privacy, 1999.
[44]
Ulfar Erlingsson and F. B. Schneider, Sasi enforcement
of security policies: a retrospective, in Proceedings of the
Workshop on New Security Paradigms. New York, NY, USA:
ACM, 2000.
496
Authorized licensed use limited to: Jaypee Institute of Technology. Downloaded on July 22,2010 at 07:16:10 UTC from IEEE Xplore. Restrictions apply.