gradual typing embedded securely in javascript
DESCRIPTION
Gradual typing Embedded securely in javascript. Aseem Rastogi. University of Maryland, College Park. Joint Work With: Nikhil Swamy , Cédric Fournet , Karthikeyan Bhargavan , Juan Chen, Pierre-Yves Strub , Gavin Bierman. Architecture of JavaScript Applications. Untrusted (e.g. ads). - PowerPoint PPT PresentationTRANSCRIPT
1
GRADUAL TYPING EMBEDDED SECURELY IN JAVASCRIPT
Aseem RastogiUniversity of Maryland, College Park
Joint Work With:
Nikhil Swamy, Cédric Fournet, Karthikeyan Bhargavan, Juan Chen, Pierre-Yves Strub, Gavin Bierman
POPL'14 TS*
2
Architecture of JavaScript Applications
POPL'14 TS*
Application
Libraries(e.g. JQuery)
Untrusted(e.g. ads)
Shared Global State(e.g. Object.prototype, String.prototype, Array.prototype)
All scripts execute in the same environment
3
At Least It’s Dynamically Type Safe
POPL'14 TS*
var x = 0; x(17); ~>* TypeError /* cannot apply a non-function */
Provides some useful security propertiesvar x = 0x1234567; x.f(); ~>* TypeError /* cannot forge an address */
4
function protect(rawSend) { var whitelist = { “www.microsoft.com/mail” : true, “www.microsoft.com/owa” : true }; return function(url, msg) { if(whitelist[url]) rawSend(msg); }}
Or Is It ?
POPL'14 TS*
function send(url, msg){ /* e.g. XMLHttpRequest */ …}
Object.prototype[“evil.com”] = true;
• Goal : Protect the send message function to restrict malicious URLs
send(“evil.com”, “gotcha”);
Attacker Succeeds !
Also looks up in Object.prototypewindow.send = protect(send);
5
Type Errors ≈ Security Vulnerabilities
POPL'14 TS*
• Attacker can exploit missing property accesses• Can execute arbitrary JavaScript
Need a stronger notion of type safety !
6
Stronger Type Safety for JavaScript ?DJS (Chugh et. al.), DJS(Maffeis et. al.), JSVerify(Swamy et. al.), JSVerify(Gardner et. al.), Adsafety(Guha et. al.), SES-light(Taly et. al.), Moller et. al., …
POPL'14 TS*
Handle only subsets of JavaScript
• Cannot ignore the adversary
• Lots of crazy stuff• eval• Proxies• Stack walking• Prototype poisoning• Global namespace corruption• …
7
Attempts to Handle Full JavaScript ?• TypeScript, Closure• Great in increasing programmer productivity• But Not Type Safe
POPL'14 TS*
8
We ask …• Can we provide stronger JS type safety
• While accounting for the full ECMAScript5 language• Unrestricted adversary
• And still retaining idiomatic JS programming interface
TS*POPL'14
9
TS★: Gradual Type System for All of JavaScriptStatically typed core
• number, bool, string• T1 T2 • { fi : Ti } (mutable, extensible) • ADTs
Dynamically typed fragment• any• JSON• Runtime type tests
Un typed adversary• arbitrary JavaScript• unmodified• unverified• unrestricted
Run time checks mediate interactions
TS*POPL'14
U
D S
10
Key Invariants of TS★
TS*POPL'14
U
D S
Static Safety:Statically typed code is safe without any runtime checks
Dynamic Safety:Runtime types are always refinements of static types
Memory Isolation:No un-location referenced directly in static/any codeNo static/any reference leaked to un-code
11
Key Idea: Gradual Security
ad.js
lib.js
app.js
function protect(rawSend) { var whitelist = { “www.microsoft.com/mail” : true, “www.microsoft.com/owa” : true }; return function(url, msg) { if(whitelist[url]) rawSend(msg); }}
TS*POPL'14
• Identify security critical code
12
Key Idea: Gradual Security
ad.js
lib.js
app.js
TS*POPL'14
function protect(rawSend)function protect(rawSend:(string,string)=>any){ var whitelist = { “www.microsoft.com/mail” : true, “www.microsoft.com/owa” : true }; return function(url:string, msg:string) { if(whitelist[url]) rawSend(msg); }}
• Identify security critical code
• Port to TS★
13
Key Idea: Gradual Security
ad.js
lib.js
app.js
TS*POPL'14
function protect(rawSend)function protect(rawSend:(string,string)=>any){ var whitelist = { “www.microsoft.com/mail” : true, “www.microsoft.com/owa” : true }; return function(url:string, msg:string) { if(whitelist[url]) rawSend(msg); }}
• Identify security critical code
• Port to TS★
function protected() { function protect(rawSend) { … } return wrap<Un>(protect);}window.send = protected();
TS★
• Compile
14
Key Idea: Gradual Security
ad.js
lib.js
app.js
TS*POPL'14
function protect(rawSend)
• Identify security critical code
• Port to TS★
• Compilefunction protected() { function protect(rawSend) { … } return wrap<Un>(protect);}window.send = protected();
• Drop-in in the app
function protect(rawSend:(string,string)=>any){ var whitelist = { “www.microsoft.com/mail” : true, “www.microsoft.com/owa” : true }; return function(url:string, msg:string) { if(whitelist[url]) rawSend(msg); }}
TS★
15
Gradual Security – Initial Experience• OWASP CSRFGuard and Facebook API
• Reported many attacks• Both widely used and security critical libraries• Ported critical fragments to TS★
• Easy to argue correctness in the presence of memory isolation
• Secure, High Integrity, and Efficient HTML5 localStorage
POPL'14 TS*
(http://rise4fun.com/FStar/tutorial/tsStar)
16
TS★ Gradual Typing Overview
POPL'14 TS*
U
D S
Based on runtime type information (RTTI)
Point { x = 2, y = 3 }
type Point = { x:number; y:number }
Compiled as is
Compiled with runtime checks to respect RTTI tags
Library provided wrappers ensure memory isolation
17
var o = { x : true };o.x = 2; o.y = 3;
diag(o);
function bar(q){ q.x = true;}
TS★ Tour with Example
type Point = { x:number; y:number }
function diag(p:Point) : Point{ bar(p); p.x = p.y; return p;}
TS★
JS
TS*POPL'14
18
var o = { x : true };o.x = 2; o.y = 3;
diag(o);
function bar(q){ q.x = true;}
Compilation of Statically Typed Code
type Point = { x:number; y:number }
function diag(p:Point) : Point{ bar(p); p.x = p.y; return p;}
TS★
JS
TS*POPL'14
function diag(p){ bar(p); p.x = p.y; return p;}
(Statically typed code is safe as is)
19
var o = { x : true };o.x = 2; o.y = 3;
diag(o);
function bar(q){ q.x = true;}
RTTI Instrumentation
type Point = { x:number; y:number }
function diag(p:Point) : Point{ bar(p); p.x = p.y; return p;}
TS★
JS
TS*POPL'14
diag.rtti = [[Point Point]]
function diag(p){ bar(p); p.x = p.y; return p;}
(Statically typed code is safe as is)
20
var o = { x : true };o.x = 2; o.y = 3;
diag(o);
function bar(q){ q.x = true;}
RTTI Instrumentation
type Point = { x:number; y:number }
function diag(p:Point) : Point{ bar(p); p.x = p.y; return p;}
TS★
JS
TS*POPL'14
diag.rtti = [[Point Point]]
function diag(p){ bar(p); p.x = p.y; return p;}
(Statically typed code is safe as is)
(Compiled with runtime type checks)
21
var o = { x : true };o.x = 2; o.y = 3;
diag(o);
function bar(q){ q.x = true;}
◄
Runtime Checks on RTTI (Dynamic Safety)
type Point = { x:number; y:number }
function diag(p:Point) : Point{ bar(p); p.x = p.y; return p;}
TS★
JS
any { x = true }
o:
TS*POPL'14
22
var o = { x : true };o.x = 2; o.y = 3;
diag(o);
function bar(q){ q.x = true;}
◄
Runtime Checks on RTTI (Dynamic Safety)
type Point = { x:number; y:number }
function diag(p:Point) : Point{ bar(p); p.x = p.y; return p;}
TS★
JS
any { x = true }
o:
Is o a record ? Does o.x = 2 respect o’s rtti ? ✔
any { x = 2 }
o:
TS*POPL'14
23
var o = { x : true };o.x = 2; o.y = 3;
diag(o);
function bar(q){ q.x = true;}
◄
Runtime Checks on RTTI (Dynamic Safety)
type Point = { x:number; y:number }
function diag(p:Point) : Point{ bar(p); p.x = p.y; return p;}
TS★
JS
any { x = true }
o:
Is o a record ? Does o.y = 3 respect o’s rtti ? ✔
any { x = 2 }
o:
any { x = 2, y = 3 }
o:
TS*POPL'14
24
var o = { x : true };o.x = 2; o.y = 3;
diag(o);
function bar(q){ q.x = true;}
◄
Dynamically Typed to Statically Typed
type Point = { x:number; y:number }
function diag(p:Point) : Point{ bar(p); p.x = p.y; return p;}
TS★
JS
any { x = 2, y = 3 }
o:
TS*POPL'14
25
var o = { x : true };o.x = 2; o.y = 3;
diag(o);
function bar(q){ q.x = true;}
◄
Attempt 1 : Use Higher Order Casts for Mutable Records
type Point = { x:number; y:number }
function diag(p:Point) : Point{ bar(p); p.x = p.y; return p;}
TS★
JS
TS*POPL'14
var o’ ={ get x() { if hasOwnProperty(o, “x”) … }; get y() { … }; set x(v) { … }; set y(v) { … };}diag(o’);
26
var o = { x : true };o.x = 2; o.y = 3;
diag(o);
function bar(q){ q.x = true;}
◄
Problems with Higher Order Casts
type Point = { x:number; y:number }
function diag(p:Point) : Point{ bar(p); p.x = p.y; return p;}
TS★
JS
TS*POPL'14
var o’ ={ get x() { … }; get y() { … }; set x(v) { … }; set y(v) { … };}diag(o’);
1. Lazy failures in statically typed code• Undesirable for security critical applications• Performance penalty for casts reduction
2. Space inefficient• Might recover with fancy coercion reductions
3. Breaks object identity• o === o’ ?
27
var o = { x : true };o.x = 2; o.y = 3;
diag(o);
function bar(q){ q.x = true;}
◄
Gradual Typing with RTTI
type Point = { x:number; y:number }
function diag(p:Point) : Point{ bar(p); p.x = p.y; return p;}
TS★
JS
✔
any { x = 2, y = 3 }
o:
Does o look like a Point ? If so, tag it. (setTag)
Point { x = 2, y = 3 }
o, p:
TS*POPL'14
28
Monotonic Evolution of RTTI
POPL'14 TS*
t0
v0t2
v2t1
v1tn
vn
v0:t0
v1:t1
v2:t2 vn:tn
…
RTTI is always a sound approximation of a runtime value
RTTI evolves monotonically w.r.t the subtyping relation
t0 :> t1 :> t2 :> … :> tn
29
type Point = { x:number; y:number }
function diag(p:Point) : Point{ bar(p); p.x = p.y; return p;}
var o = { x : true };o.x = 2; o.y = 3;
diag(o);
function bar(q){ q.x = true;}
◄
Seamless Transition from Statically Typed to Dynamically Typed
TS★
JS
Seamless via subtyping – Point <: any.
Point { x = 2, y = 3 }
o, p:
TS*POPL'14
30
function bar(q){ q.x = true;}
type Point = { x:number; y:number }
function diag(p:Point) : Point{ bar(p); p.x = p.y; return p;}
var o = { x : true };o.x = 2; o.y = 3;
diag(o);
◄
RTTI Violations Cause Runtime Failures
TS★
JS
Point { x = 2, y = 3 }
o, p, q:
Is q a record ? Does q.x = true respect q’s rtti ? ✗ Runtime failure
TS*POPL'14
31
function bar(q){ q.color = “red”;}
type Point = { x:number; y:number }
function diag(p:Point) : Point{ bar(p); p.x = p.y; return p;}
var o = { x : true };o.x = 2; o.y = 3;
diag(o);
◄
Runtime Checks on RTTI (Dynamic Safety)
TS★
JS
Point { x = 2, y = 3 }
o, p, q:
Is q a record ? Does q.color = “red” respect q’s rtti ? ✔
Point { x = 2, y = 3, color = “red” }
o, p, q:
TS*POPL'14
32
function bar(q){ q.color = “red”;}
type Point = { x:number; y:number }
function diag(p:Point) : Point{ bar(p); p.x = p.y; return p;}
var o = { x : true };o.x = 2; o.y = 3;
diag(o);
◄
Statically Typed Code Executes As Is
TS★
JS
Point { x = 2, y = 3, color = “red” }
o, p, q:
Executes as expected, without any checks.
TS*POPL'14
33
Key Invariants of TS★
TS*POPL'14
U
D S
Static Safety:Statically typed code is safe without any runtime checks
Dynamic Safety:Runtime types are always refinements of static types
Memory Isolation:No un-location referenced directly in static/any codeNo static/any reference leaked to un-code
34
type Point = { x:number; y:number }
function diag(p:Point) : Point{ baz(p); p.x = p.y; return p;}
function baz(q){ …}
Memory Isolation from Un
TS★
JS
Unmodified, unverified, unrestricted.
TS*POPL'14
35
type Point = { x:number; y:number }
function diag(p:Point) : Point{ baz(p); p.x = p.y; return p;}
function baz(q){ delete q.x; }
Memory Isolation from Un
TS★
JS
Unmodified, unverified, unrestricted.
TS*POPL'14
function baz(q){ delete q.rtti; }
function baz(q){ q.rtti = “junk”; }
How to protect invariants ?
36
type Point = { x:number; y:number }
baz : Un
function diag(p:Point) : Point{ baz(p); p.x = p.y; return p;}
function baz(q){ …}
Memory Isolation from Un
TS★
• A second dynamic type Un
• Abstract type: not related to any other type
• Point <: any <\: Un
• { f : number; g : Un } <: { g : Un } <\: { }
TS*POPL'14
37
type Point = { x:number; y:number }
baz : Un
function diag(p:Point) : Point{ baz(p); p.x = p.y; return p;}
function baz(q){ …}
Memory Isolation from Un
TS★
Compile error: Cannot apply an Un typed term
TS*POPL'14
38
type Point = { x:number; y:number }
baz : Un
function diag(p:Point) : Point{ wrap<Un, Point any>(baz)(p); p.x = p.y; return p;}
function baz(q){ …}
Memory Isolation from Un
TS★
Library provided wrappers, ensure memory isolation
TS*POPL'14
39
Wrappers Enforce Heap Shape Invariant
POPL'14 TS*
un fragmentStatic and any-typed DMZ(stubs)
• Non-Un values completely independent of untrusted global state (prototypes etc.) – thus send/protect example is secure in TS★
• TS★ runtime system needs “first starter privileges” on the page
40
Facebook API Example
POPL'14 TS*
Untrusted web page Facebook API
Iframe
Retrieves user’s access token
Gives access token to the untrusted page if it’s authorized by user
Wants to connect to Facebook on current user’s credentials
41
Facebook API Sample Code
POPL'14 TS*
function decode(s){ var res = { }; if(s === “”) return res; var p = String.split(s,“&”); for(var k in p) { var kv = String.split(p[k],“=“); res[kv[“0”]] = kv[“1”]; } return res;}
function checkOrigins(g, e){ for(var k in e) { if(g === e[k]) return true; } return false;}
42
Example Vulnerabilities in Facebook API
POPL'14 TS*
function checkOrigins(g, e){ for(var k in e) { if(g === e[k]) return true; } return false;}
Attacks similar toprotect/send(Using Object.prototype)
function decode(s){ var res = { }; if(s === “”) return res; var p = String.split(s,“&”); for(var k in p) { var kv = String.split(p[k],“=“); res[kv[“0”]] = kv[“1”]; } return res;}
43
function decode(s:string):any{ var res = { }; if(s === “”) return res; var p = String.split(s,“&”); for(var k in p) { var kv = String.split(p[k],“=“); res[kv[“0”]] = kv[“1”]; } return res;}
Porting Facebook API to TS★
POPL'14 TS*
function checkOrigins(g:string, e:array string):bool{ for(var k in e) { if(g === e[k]) return true; } return false;}
44
Also in the paper …• More details on the wrappers• Formal translation from TS★ to JavaScript• Formalization of TS★ in JSVerify†
• Type soundness theorem and proof sketch• A standards based mechanism for first starter privileges• More examples
†Swamy et. al. PLDI’ 13
See our paper !
TS*POPL'14
45
TS★:The First JavaScript Type System To
• Provide strong type safety in a modular way• While accounting for ALL of JavaScript
http://research.microsoft.com/en-us/um/people/nswamy/Playground/TSSecure/index.html
POPL'14 TS*