Upload
others
View
15
Download
0
Embed Size (px)
Citation preview
ADsafetyType-based Verification of JavaScript Sandboxing
Joe Gibbs PolitzSpiridon Aristides Eliopoulos
Arjun GuhaShriram Krishnamurthi
1
2
3
4
third-party ad
third-party ad
5
Who is running code in your
browser?
5
Who is running code in your
browser?
5
Who is running code in your
browser?
the host you visit
6
the host you visit
6
the host you visit the ad server
6
the host you visit the ad server
6
same JavaScript context
the host you visit the ad server
6
<iframe>
the host you visit the ad server
6
<iframe>
top.location.href
Facebook JavaScript (FBJS)
GoogleCaja
Yahoo!ADsafe
All are defining safe sub-languages
7
Microsoft Web Sandbox
8
eval
8
eval
8
evale
8
evale
wrap(e)
8
wrap
evale
wrap(e)
8
wrap
evale
wrap(e)
“filters”
“wrappers”
— Maffeis, Mitchell, and Taly, ESORICS 2009
“rew
riter
s”8
9
eval
9
eval
ADSAFE.get(obj, x)
9
untrusted widget
ADSAFE.get
eval
ADSAFE.get(obj, x)
9
untrusted widget
• 1, 800 LOC adsafe.js library
• 50 calls to three kinds of assertions
• 40 type-tests
• 5 regular-expression based checks
• 60 privileged DOM method calls
10
• 1, 800 LOC adsafe.js library
• 50 calls to three kinds of assertions
• 40 type-tests
• 5 regular-expression based checks
• 60 privileged DOM method calls
10
?
Type-based Verification of
11
Definition 1 (ADsafety): If all embedded widgets pass JSLint, then:
12
Definition 1 (ADsafety): If all embedded widgets pass JSLint, then: eval()
document.write()document.createElement("script")
...1.Widgets cannot load new code at runtime, or cause ADsafe to load new code on their behalf;
12
Definition 1 (ADsafety): If all embedded widgets pass JSLint, then: eval()
document.write()document.createElement("script")
...1.Widgets cannot load new code at runtime, or cause ADsafe to load new code on their behalf;
12
Definition 1 (ADsafety): If all embedded widgets pass JSLint, then:
1.Widgets cannot load new code at runtime, or cause ADsafe to load new code on their behalf;
2.Widgets cannot obtain direct references to DOM nodes;
<div>
<p> <div>
<b>
ADsafeUntrusted
Widget
12
Definition 1 (ADsafety): If all embedded widgets pass JSLint, then:
1.Widgets cannot load new code at runtime, or cause ADsafe to load new code on their behalf;
2.Widgets cannot obtain direct references to DOM nodes;
<div>
<p> <div>
<b>
ADsafeUntrusted
Widget
12
Definition 1 (ADsafety): If all embedded widgets pass JSLint, then:
1.Widgets cannot load new code at runtime, or cause ADsafe to load new code on their behalf;
2.Widgets cannot obtain direct references to DOM nodes;
3.Widgets cannot affect the DOM outside of their subtree; and
<div id="WIDGET">
<p> <div>
<b>
ADsafeUntrusted
Widget
<div>
12
Definition 1 (ADsafety): If all embedded widgets pass JSLint, then:
1.Widgets cannot load new code at runtime, or cause ADsafe to load new code on their behalf;
2.Widgets cannot obtain direct references to DOM nodes;
3.Widgets cannot affect the DOM outside of their subtree; and
<div id="WIDGET">
<p> <div>
<b>
ADsafeUntrusted
Widget
<div>
12
Definition 1 (ADsafety): If all embedded widgets pass JSLint, then:
1.Widgets cannot load new code at runtime, or cause ADsafe to load new code on their behalf;
2.Widgets cannot obtain direct references to DOM nodes;
3.Widgets cannot affect the DOM outside of their subtree; and
4.Multiple widgets on the same page cannot communicate.
ADsafeWidget A Widget B
12
13
ADSAFE.get
eval
ADSAFE.get(obj, x)
Goal: Verify ADsafe
13
ADSAFE.get
eval
ADSAFE.get(obj, x)
Goal: Verify ADsafe
untrusted, but passes JSLint
13
ADSAFE.get
eval
ADSAFE.get(obj, x)
Goal: Verify ADsafe
untrusted, but passes JSLint
Goal: model JSLint
14
JSLint ensures: no DOM references
node
“Widgets cannot obtain direct references to DOM nodes.”
<div>
<p> <div>
<b>
ADsafeUntrusted
Widget
14
bunch = { __nodes__ : array of nodes, append: function ..., getText: function ..., ... 20 functions}
ADsafe ensures: only “safe”
methods on bunches
JSLint ensures: no DOM references
node
“Widgets cannot obtain direct references to DOM nodes.”
<div>
<p> <div>
<b>
ADsafeUntrusted
Widget
14
bunch = { __nodes__ : array of nodes, append: function ..., getText: function ..., ... 20 functions}
ADsafe ensures: only “safe”
methods on bunches
bunch.__nodes__
No private fields in JavaScript!
JSLint ensures: no DOM references
node
“Widgets cannot obtain direct references to DOM nodes.”
<div>
<p> <div>
<b>
ADsafeUntrusted
Widget
14
bunch = { __nodes__ : array of nodes, append: function ..., getText: function ..., ... 20 functions}
ADsafe ensures: only “safe”
methods on bunches
JSLint ensures: __nodes__ is
“private”bunch.__nodes__
JSLint ensures: no DOM references
node
“Widgets cannot obtain direct references to DOM nodes.”
<div>
<p> <div>
<b>
ADsafeUntrusted
Widget
14
bunch = { __nodes__ : array of nodes, append: function ..., getText: function ..., ... 20 functions}
ADsafe ensures: only “safe”
methods on bunches
JSLint ensures: __nodes__ is
“private”
bunch.append(...)
bunch.__nodes__
JSLint ensures: no DOM references
node
“Widgets cannot obtain direct references to DOM nodes.”
<div>
<p> <div>
<b>
ADsafeUntrusted
Widget
Exploit append to return nodes?
14
bunch = { __nodes__ : array of nodes, append: function ..., getText: function ..., ... 20 functions}
ADsafe ensures: only “safe”
methods on bunches
JSLint ensures: __nodes__ is
“private”
bunch.append(...)ADsafe ensures: DOM nodes are
not returned
bunch.__nodes__
JSLint ensures: no DOM references
node
“Widgets cannot obtain direct references to DOM nodes.”
<div>
<p> <div>
<b>
ADsafeUntrusted
Widget
15
ADSAFE.get
eval
ADSAFE.get(obj, x)
Goal 2: Verify ADsafe
untrusted, but passes JSLint
Goal 1: model JSLint
var n = 6var s = "a string"var b = true
16
var n = 6var s = "a string"var b = true
16
Widget := Number + String + Boolean + Undefined + Null +
17
Widget := Number + String + Boolean + Undefined + Null +
{ x: 6, b: "car" }
17
Widget := Number + String + Boolean + Undefined + Null +
★: Widget__nodes__: Array<Node>caller: �prototype: �...code : Widget ⨉ ... → Widget__proto__: Object + Function + Array + ...
{ x: 6, b: "car" }{ nested: { y: 10, b: false } }
17
Widget := Number + String + Boolean + Undefined + Null +
★: Widget__nodes__: Array<Node>caller: �prototype: �...code : Widget ⨉ ... → Widget__proto__: Object + Function + Array + ...
{ x: 6, b: "car" }{ nested: { y: 10, b: false } }{ __nodes__: 90 }myObj.prototype = { };
17
Widget := Number + String + Boolean + Undefined + Null +
★: Widget__nodes__: Array<Node>caller: �prototype: �...code : Widget ⨉ ... → Widget__proto__: Object + Function + Array + ...
{ x: 6, b: "car" }{ nested: { y: 10, b: false } }{ __nodes__: 90 }myObj.prototype = { };function foo(x) { return x + 1; }foo(900)foo.w = "functions are objects"["array", "of", "strings"]/regular[ \t]*expressions/
17
Widget := Number + String + Boolean + Undefined + Null +
JSLint Widget type-checker
typable widgets
widgets that pass JSLint
18
JSLint Widget type-checker
typable widgets
widgets that pass JSLint
or, passing JSLint ⇒Widget-typable
Claim:evidence:1,100 LOC of tests
18
JSLint Widget type-checker
typable widgets
widgets that pass JSLint
or, passing JSLint ⇒Widget-typable
type-based arguments about
widgets
Claim:evidence:1,100 LOC of tests
18
19
ADSAFE.get
eval
ADSAFE.get(obj, x)
untrusted, but passes JSLint
Goal 1: model JSLint
Goal 2: Verify ADsafe
20
window.setTimeout(callback, delay);
eval
window.setTimeout
Widget→Widget
String
20
window.setTimeout(callback, delay);
eval
window.setTimeout
Widget→Widget
String
String
Widget→Widget
Widget→Widget
Object
Number
/*: Widget ⨉ Widget → Widget */ADSAFE.later = function(callback, delay) { if (typeof callback !== "function") { throw "expected function"; }
}
20
window.setTimeout(callback, delay);
window : { eval: ☠, setTimeout : (Widget ⨉ ... → Widget) ⨉ Widget → Undefined, ...}
eval
window.setTimeout
Widget→Widget
String
String
Widget→Widget
Widget→Widget
Object
Number
/*: Widget ⨉ Widget → Widget */ADSAFE.later = function(callback, delay) { if (typeof callback !== "function") { throw "expected function"; }
}
20
window.setTimeout(callback, delay);
window : { eval: ☠, setTimeout : (Widget ⨉ ... → Widget) ⨉ Widget → Undefined, ...}
eval
window.setTimeout
Widget→Widget
String
String
Widget→Widget
Widget→Widget
Object
Number
/*: Widget ⨉ Widget → Widget */ADSAFE.later = function(callback, delay) { if (typeof callback !== "function") { throw "expected function"; }
}
Widget
20
window.setTimeout(callback, delay);
window : { eval: ☠, setTimeout : (Widget ⨉ ... → Widget) ⨉ Widget → Undefined, ...}
Widget ⨉ ... → Widgeteval
window.setTimeout
Widget→Widget
String
String
Widget→Widget
Widget→Widget
Object
Number
/*: Widget ⨉ Widget → Widget */ADSAFE.later = function(callback, delay) { if (typeof callback !== "function") { throw "expected function"; }
}
Widget
20
window.setTimeout(callback, delay);
window : { eval: ☠, setTimeout : (Widget ⨉ ... → Widget) ⨉ Widget → Undefined, ...}
Widget ⨉ ... → Widget
—Politz et al. USENIX Security 2011 and Guha, Saftoiu, Krishnamurthi. ESOP 2011.
eval
window.setTimeout
Widget→Widget
String
String
Widget→Widget
Widget→Widget
Object
Number
/*: Widget ⨉ Widget → Widget */ADSAFE.later = function(callback, delay) { if (typeof callback !== "function") { throw "expected function"; }
}
Widget
This is just one kind of if-split we handle.
JSLinted widgetadsafe.js
21
JSLinted widgetadsafe.js
21
JSLinted widgetadsafe.js
21
JSLinted widget
WidgetW
idget
Wid
get
Wid
get
adsafe.js21
JSLinted widget
WidgetW
idget
Wid
get
Wid
get
adsafe.js21
JSLinted widget
WidgetW
idget
Wid
get
Wid
get
adsafe.js
Widget
Widget
Widget
Widget
21
JSLinted widget
WidgetW
idget
Wid
get
Wid
get
adsafe.js
Widget
Widget
Widget
Widget
Arr
ay<N
ode>
Nod
e
21
JSLinted widget
WidgetW
idget
Wid
get
Wid
get
adsafe.js
Widget
Widget
Widget
Widget
Arr
ay<N
ode>
Nod
e
Node
Node
21
22
typable widgets
widgets that pass JSLint
JSLinted widget
WidgetW
idget
Wid
get
Wid
get
adsafe.js
Widget
Widget
Widget
Widget
Arr
ay<N
ode>
Nod
e
JSLint model Type-checked ADsafe
+ = ⋯
23
typable widgets
widgets that pass JSLint
var fakeNode = { tagName: "div", appendChild: function(elt) { var win = elt.ownerDocument.defaultView; win.eval("alert('hacked')"); }};
23
typable widgets
widgets that pass JSLint
var fakeNode = { tagName: "div", appendChild: function(elt) { var win = elt.ownerDocument.defaultView; win.eval("alert('hacked')"); }};var fakeBunch = { __nodes__: [fakeNode] };
Rejected by JSLint
23
typable widgets
widgets that pass JSLint
var fakeNode = { tagName: "div", appendChild: function(elt) { var win = elt.ownerDocument.defaultView; win.eval("alert('hacked')"); }};var fakeBunch = { __nodes__: [fakeNode] };
Rejected by JSLint
var fakeBunch = { '__nodes__': [fakeNode] };
Accepted by JSLint
type error: expected Array<HTML>, received Array<Widget>
/*: Widget ⨉ Widget → Widget */WrappedElt.prototype.style = function(name, val) { var regexp = new Regexp("url"); if (regexp.test(val)) { return error(); } ... this.__node__.style[name] = val ...}
24
/*: Widget ⨉ Widget → Widget */WrappedElt.prototype.style = function(name, val) { var regexp = new Regexp("url"); if (regexp.test(val)) { return error(); } ... this.__node__.style[name] = val ...}
expected String, received
Widget
24
/*: Widget ⨉ Widget → Widget */WrappedElt.prototype.style = function(name, val) { var regexp = new Regexp("url"); if (regexp.test(val)) { return error(); } ... this.__node__.style[name] = val ...}
expected String, received
Widget
var firstCall = true;var badName = { toString: function() { if (firstCall) { firstCall = false; return "font"; } else { return "url('/evil.xml')"; } }};
passes safety check
returns bad value
24
/*: Widget ⨉ Widget → Widget */WrappedElt.prototype.style = function(name, val) { var regexp = new Regexp("url"); if (regexp.test(val)) { return error(); } ... this.__node__.style[name] = val ...}
expected String, received
Widget
var firstCall = true;var badName = { toString: function() { if (firstCall) { firstCall = false; return "font"; } else { return "url('/evil.xml')"; } }};
passes safety check
returns bad value
Fix: check_string
assertion inserted here, and in 16 other places
24
Definition 1 (ADsafety): If all embedded widgets pass JSLint, then:
eval()document.write()
document.createElement("script")...
1.Widgets cannot load new code at runtime, or cause ADsafe to load new code on their behalf;
2.Widgets cannot obtain direct references to DOM nodes;
3.Widgets cannot affect the DOM outside of their subtree; and
4.Multiple widgets on the same page cannot communicate.
<div>
<p> <div>
<b>
ADsafeUntrusted
Widget
<div id="WIDGET">
<p> <div>
<b>
ADsafeUntrusted
Widget
<div>
ADsafeWidget A Widget B
25
Definition 1 (ADsafety): If all embedded widgets pass JSLint, then:
eval()document.write()
document.createElement("script")...
1.Widgets cannot load new code at runtime, or cause ADsafe to load new code on their behalf;
2.Widgets cannot obtain direct references to DOM nodes;
3.Widgets cannot affect the DOM outside of their subtree; and
4.Multiple widgets on the same page cannot communicate.
<div>
<p> <div>
<b>
ADsafeUntrusted
Widget
<div id="WIDGET">
<p> <div>
<b>
ADsafeUntrusted
Widget
<div>
ADsafeWidget A Widget B
25
Definition 1 (ADsafety): If all embedded widgets pass JSLint, then:
eval()document.write()
document.createElement("script")...
1.Widgets cannot load new code at runtime, or cause ADsafe to load new code on their behalf;
2.Widgets cannot obtain direct references to DOM nodes;
3.Widgets cannot affect the DOM outside of their subtree; and
4.Multiple widgets on the same page cannot communicate.
<div>
<p> <div>
<b>
ADsafeUntrusted
Widget
<div id="WIDGET">
<p> <div>
<b>
ADsafeUntrusted
Widget
<div>
ADsafeWidget A Widget B
25
Definition 1 (ADsafety): If all embedded widgets pass JSLint, then:
eval()document.write()
document.createElement("script")...
1.Widgets cannot load new code at runtime, or cause ADsafe to load new code on their behalf;
2.Widgets cannot obtain direct references to DOM nodes;
3.Widgets cannot affect the DOM outside of their subtree; and
4.Multiple widgets on the same page cannot communicate.
<div>
<p> <div>
<b>
ADsafeUntrusted
Widget
<div id="WIDGET">
<p> <div>
<b>
ADsafeUntrusted
Widget
<div>
ADsafeWidget A Widget B
25
Definition 1 (ADsafety): If all embedded widgets pass JSLint, then:
eval()document.write()
document.createElement("script")...
1.Widgets cannot load new code at runtime, or cause ADsafe to load new code on their behalf;
2.Widgets cannot obtain direct references to DOM nodes;
3.Widgets cannot affect the DOM outside of their subtree; and
4.Multiple widgets on the same page cannot communicate.
<div>
<p> <div>
<b>
ADsafeUntrusted
Widget
<div id="WIDGET">
<p> <div>
<b>
ADsafeUntrusted
Widget
<div>
ADsafeWidget A Widget BRetracte
d
25
Caveats:
• 11 LOC unverified
• subtree property unverified
26
!
JavaScriptprogram
Proofs for JavaScript?
27
JavaScriptprogram
λJS
programdesugar
Proofs for JavaScript?
Proofs for λJS.
27
JavaScriptprogram
λJS
program
“theiranswer”
“ouranswer”
desugar
SpiderMonkey, V8, Rhino
100 LOC interpreter
identical forMozilla JS test suite*
Proofs for JavaScript?
Proofs for λJS.
— Guha, Saftoiu, Krishnamurthi. ECOOP 2010.
27
banned = { 'arguments' : true, callee : true, caller : true, constructor : true, 'eval' : true, prototype : true, stack : true, unwatch : true, valueOf : true, watch : true}
function reject_global(that) { if (that.window) { error(); }}+ if (/url/i.test(string_check(value[i]))) {
error('ADsafe error.');}+
and other patterns...
28
banned = { 'arguments' : true, callee : true, caller : true, constructor : true, 'eval' : true, prototype : true, stack : true, unwatch : true, valueOf : true, watch : true}
function reject_global(that) { if (that.window) { error(); }}+ if (/url/i.test(string_check(value[i]))) {
error('ADsafe error.');}+
and other patterns...
28
... can be succinctly expressed with typesWidget := Number + String + Boolean + Undefined + Null +
★: Widget__nodes__: Array<Node>caller: �prototype: �...code : Widget ⨉ ... → Widget__proto__: Object + Function + Array + ...
★: Widget__proto__: Object + Function + Array + ...code : Widget ⨉ ... → Widgetarguments: �caller: �...
Widget := Number + String + Boolean + Undefined + Null +
JavaScriptprogram
λJS
program
“theiranswer”
“ouranswer”
SpiderMonkey, V8, Rhino
100 LOC interpreter
desugar
identical forMozilla JS test suite*
wrap wrap(e)
eeval
untypable
typable
typable
1.Model sandbox as a type system
2.Object types for JavaScript (★ and ☠)
3.Proofs over tractable JavaScript semantics
Conclusion
29
Extra Slides30
Spiridon Aristides Eliopoulos
Unverified Code
31
function F() {};
ADSAFE.create = typeof Object.create === 'function' ? Object.create : function (o) { F.prototype = typeof o === 'object' && o ? o : Object.prototype; return new F();};
/*: (banned → True) & (not_banned → False) */function reject_name(name) { return banned[name] || ((typeof name !== 'number' || name < 0) && (typeof name !== 'string' || name.charAt(0) === '_' || name.slice(-1) === '_' || name.charAt(0) === '-'));}
Theorems
32
Full Widget Type
33