Joe Gibbs Politz Spiridon Aristides Eliopoulos Arjun Guha Shriram Krishnamurthi 1 2 3 Third-Party Ad
Total Page:16
File Type:pdf, Size:1020Kb
ADsafety Type-based Verification of JavaScript Sandboxing Joe Gibbs Politz Spiridon Aristides Eliopoulos Arjun Guha Shriram Krishnamurthi 1 2 3 third-party ad third-party ad 4 Who is running code in your browser? 5 Who is running code in your browser? 5 Who is running code in your browser? 5 the host you visit 6 the host you visit 6 the host the ad server you visit 6 the host the ad server you visit same JavaScript context 6 the host the ad server you visit <iframe> 6 the host the ad server you visit <iframe> top.location.href 6 Microsoft Web Sandbox Google Facebook JavaScript Caja (FBJS) Yahoo! ADsafe All are defining safe sub-languages 7 8 eval 8 eval 8 eval e 8 eval e wrap(e) 8 eval e wrap wrap(e) 8 “filters” “wrappers” eval e “rewriters” wrap wrap(e) — Maffeis, Mitchell, and Taly, ESORICS 2009 8 9 eval 9 eval ADSAFE.get(obj, x) untrusted widget 9 eval ADSAFE.get ADSAFE.get(obj, x) untrusted widget 9 • 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 <div> references to DOM nodes; Untrusted <p> <div> ADsafe Widget <b> 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 <div> references to DOM nodes; Untrusted <p> <div> ADsafe Widget <b> 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 <div> references to DOM nodes; 3.Widgets cannot affect the <div id="WIDGET"> DOM outside of their subtree; and Untrusted <p> <div> ADsafe Widget <b> 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 <div> references to DOM nodes; 3.Widgets cannot affect the <div id="WIDGET"> DOM outside of their subtree; and Untrusted <p> <div> ADsafe Widget <b> 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. Widget A ADsafe Widget B 12 eval Goal: Verify ADsafe ADSAFE.get ADSAFE.get(obj, x) 13 eval Goal: Verify ADsafe ADSAFE.get ADSAFE.get(obj, x) untrusted, but passes JSLint 13 eval Goal: Verify ADsafe Goal: model JSLint ADSAFE.get ADSAFE.get(obj, x) untrusted, but passes JSLint 13 JSLint ensures: no DOM node references <div> Untrusted <p> <div> ADsafe Widget <b> “Widgets cannot obtain direct references to DOM nodes.” 14 JSLint ensures: no DOM node references ADsafe ensures: bunch = { only “safe” __nodes__ : array of nodes, methods on append: function ..., bunches getText: function ..., ... 20 functions } <div> Untrusted <p> <div> ADsafe Widget <b> “Widgets cannot obtain direct references to DOM nodes.” 14 JSLint ensures: no DOM node references ADsafe ensures: bunch = { only “safe” __nodes__ : array of nodes, methods on append: function ..., bunches getText: function ..., ... 20 functions } <div> No private fields in JavaScript! Untrusted <p> <div> ADsafe bunch.__nodes__ Widget <b> “Widgets cannot obtain direct references to DOM nodes.” 14 JSLint ensures: no DOM node references ADsafe ensures: bunch = { only “safe” __nodes__ : array of nodes, methods on append: function ..., bunches getText: function ..., ... 20 functions } <div> JSLint ensures: Untrusted <p> <div> ADsafe __nodes__ is bunch.__nodes__ Widget “private” <b> “Widgets cannot obtain direct references to DOM nodes.” 14 JSLint ensures: no DOM node references ADsafe ensures: bunch = { only “safe” __nodes__ : array of nodes, methods on append: function ..., bunches getText: function ..., ... 20 functions } <div> JSLint ensures: Untrusted <p> <div> ADsafe __nodes__ is bunch.__nodes__ Widget “private” <b> bunch.append(...) “Widgets cannot obtain direct references to DOM nodes.” Exploit append to return nodes? 14 JSLint ensures: no DOM node references ADsafe ensures: bunch = { only “safe” __nodes__ : array of nodes, methods on append: function ..., bunches getText: function ..., ... 20 functions } <div> JSLint ensures: Untrusted <p> <div> ADsafe __nodes__ is bunch.__nodes__ Widget “private” <b> ADsafe ensures: DOM nodes are bunch.append(...) “Widgets cannot obtain direct not returned references to DOM nodes.” 14 eval Goal 2: Verify ADsafe Goal 1: model JSLint ADSAFE.get ADSAFE.get(obj, x) untrusted, but passes JSLint 15 var n = 6 var s = "a string" var b = true 16 var n = 6 var s = "a string" var b = true Widget := Number + String + Boolean + Undefined + Null + 16 Widget := Number + String + Boolean + Undefined + Null + 17 { x: 6, b: "car" } Widget := Number + String + Boolean + Undefined + Null + 17 { x: 6, b: "car" } { nested: { y: 10, b: false } } Widget := Number + String + Boolean + Undefined + Null + ★: Widget __nodes__: Array<Node> caller: prototype: ... code : Widget ⨉ ... → Widget __proto__: Object + Function + Array + ... 17 { x: 6, b: "car" } { nested: { y: 10, b: false } } { __nodes__: 90 } myObj.prototype = { }; Widget := Number + String + Boolean + Undefined + Null + ★: Widget __nodes__: Array<Node> caller: prototype: ... code : Widget ⨉ ... → Widget __proto__: Object + Function + Array + ... 17 { 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/ Widget := Number + String + Boolean + Undefined + Null + ★: Widget __nodes__: Array<Node> caller: prototype: ... code : Widget ⨉ ... → Widget __proto__: Object + Function + Array + ... 17 JSLint Widget type-checker typable widgets widgets that pass JSLint 18 JSLint Widget type-checker typable widgets widgets that Claim: pass JSLint evidence: 1,100 LOC of tests or, passing JSLint ⇒Widget-typable 18 JSLint Widget type-checker type-based typable arguments about widgets widgets widgets that Claim: pass JSLint evidence: 1,100 LOC of tests or, passing JSLint ⇒Widget-typable 18 eval Goal 2: Verify ADsafe Goal 1: model JSLint ADSAFE.get ADSAFE.get(obj, x) untrusted, but passes JSLint 19 window.setTimeout(callback, delay); String eval window.setTimeout Widget→Widget 20 Object Widget →Widget String Number /*: Widget ⨉ Widget → Widget */ ADSAFE.later = function(callback, delay) { if (typeof callback !== "function") { Widget throw "expected function"; →Widget } window.setTimeout(callback, delay); String } eval window.setTimeout Widget→Widget 20 Object window : { Widget →Widget eval: ☠, setTimeout : (Widget ⨉ ... → Widget) ⨉ Widget → Undefined, String ... Number } /*: Widget ⨉ Widget → Widget */ ADSAFE.later = function(callback, delay) { if (typeof callback !== "function") { Widget throw "expected function"; →Widget } window.setTimeout(callback, delay); String } eval window.setTimeout Widget→Widget 20 Object window : { Widget →Widget eval: ☠, setTimeout : (Widget ⨉ ... → Widget) ⨉ Widget → Undefined, String ... Number } Widget /*: Widget ⨉ Widget → Widget */ ADSAFE.later = function(callback, delay) { if (typeof callback !== "function") { Widget throw "expected function"; →Widget } window.setTimeout(callback, delay); String } eval window.setTimeout Widget→Widget 20 Object window : { Widget →Widget eval: ☠, setTimeout : (Widget ⨉ ... → Widget) ⨉ Widget → Undefined, String ... Number } Widget /*: Widget ⨉ Widget → Widget */ ADSAFE.later = function(callback, delay) { if (typeof callback !== "function") { Widget throw "expected function"; →Widget } window.setTimeout(callback, delay); String } eval Widget ⨉ ... → Widget window.setTimeout Widget→Widget 20 Object window : { Widget →Widget eval: ☠, setTimeout : (Widget ⨉ ... → Widget) ⨉ Widget → Undefined, String ... Number } Widget /*: Widget ⨉ Widget → Widget */ ADSAFE.later = function(callback, delay) { if (typeof callback !== "function") { Widget throw "expected function"; →Widget } window.setTimeout(callback, delay); String } eval Widget ⨉ ... → Widget window.setTimeout This is just one kind of if-split we handle. Widget→Widget —Politz et al. USENIX Security 2011 and Guha, Saftoiu, Krishnamurthi. ESOP 2011. 20 JSLinted adsafe.js widget 21 JSLinted adsafe.js widget 21 JSLinted adsafe.js widget 21 Widget Widget Widget Widget JSLinted adsafe.js widget 21 Widget Widget Widget Widget JSLinted adsafe.js widget 21 Widget Widget Widget Widget Widget Widget