Taming JavaScript with F* Nikhil Swamy Microsoft Research.

Slides:



Advertisements
Similar presentations
Sml2java a source to source translator Justin Koser, Haakon Larsen, Jeffrey Vaughan PLI 2003 DP-COOL.
Advertisements

Transposing F to C Transposing F to C Andrew Kennedy & Don Syme Microsoft Research Cambridge, U.K.
Writing specifications for object-oriented programs K. Rustan M. Leino Microsoft Research, Redmond, WA, USA 21 Jan 2005 Invited talk, AIOOL 2005 Paris,
Program Verification Using the Spec# Programming System ETAPS Tutorial K. Rustan M. Leino, Microsoft Research, Redmond Rosemary Monahan, NUIM Maynooth.
Technologies for finding errors in object-oriented software K. Rustan M. Leino Microsoft Research, Redmond, WA Lecture 3 Summer school on Formal Models.
Technologies for finding errors in object-oriented software K. Rustan M. Leino Microsoft Research, Redmond, WA Lecture 1 Summer school on Formal Models.
Automated Theorem Proving Lecture 1. Program verification is undecidable! Given program P and specification S, does P satisfy S?
Challenges in increasing tool support for programming K. Rustan M. Leino Microsoft Research, Redmond, WA, USA 23 Sep 2004 ICTAC Guiyang, Guizhou, PRC joint.
Optional Static Typing Guido van Rossum (with Paul Prescod, Greg Stein, and the types-SIG)
Static Contract Checking for Haskell Dana N. Xu University of Cambridge Ph.D. Supervisor: Simon Peyton Jones Microsoft Research Cambridge.
De necessariis pre condiciones consequentia sine machina P. Consobrinus, R. Consobrinus M. Aquilifer, F. Oratio.
An Abstract Interpretation Framework for Refactoring P. Cousot, NYU, ENS, CNRS, INRIA R. Cousot, ENS, CNRS, INRIA F. Logozzo, M. Barnett, Microsoft Research.
Type Checking, Inference, & Elaboration CS153: Compilers Greg Morrisett.
Type Analysis and Typed Compilation Stephanie Weirich Cornell University.
A Program Transformation For Faster Goal-Directed Search Akash Lal, Shaz Qadeer Microsoft Research.
Safe TypeScript Aseem Rastogi University of Maryland, College Park
Current Techniques in Language-based Security David Walker COS 597B With slides stolen from: Steve Zdancewic University of Pennsylvania.
Simplified Gated Assignment Surinder Jain Supervisor : Bernhard Scholz Assignment 3 – INFO5993.
1 Mooly Sagiv and Greta Yorsh School of Computer Science Tel-Aviv University Modern Compiler Design.
1 How to transform an analyzer into a verifier. 2 OUTLINE OF THE LECTURE a verification technique which combines abstract interpretation and Park’s fixpoint.
1 Compiler Construction Intermediate Code Generation.
WEAVING CODE EXTENSIONS INTO JAVASCRIPT Benjamin Lerner, Herman Venter, and Dan Grossman University of Washington, Microsoft Research.
GATEKEEPER MOSTLY STATIC ENFORCEMENT OF SECURITY AND RELIABILITY PROPERTIES FOR JAVASCRIPT CODE Salvatore Guarnieri & Benjamin Livshits Presented by Michael.
ISBN Chapter 3 Describing Syntax and Semantics.
Compiler Construction
Catriel Beeri Pls/Winter 2004/5 last 55 Two comments on let polymorphism I. What is the (time, space) complexity of type reconstruction? In practice –
Data Abstraction COS 441 Princeton University Fall 2004.
K. Rustan M. Leino Research in Software Engineering (RiSE) Microsoft Research, Redmond, WA part 0 Summer School on Logic and Theorem-Proving in Programming.
Introduction to ML - Part 2 Kenny Zhu. What is next? ML has a rich set of structured values Tuples: (17, true, “stuff”) Records: {name = “george”, age.
Software Reliability Methods Sorin Lerner. Software reliability methods: issues What are the issues?
A Type System for Expressive Security Policies David Walker Cornell University.
From last time S1: l := new Cons p := l S2: t := new Cons *p := t p := t l p S1 l p tS2 l p S1 t S2 l t S1 p S2 l t S1 p S2 l t S1 p L2 l t S1 p S2 l t.
Describing Syntax and Semantics
Cormac Flanagan University of California, Santa Cruz Hybrid Type Checking.
Automatic Implementation of provable cryptography for confidentiality and integrity Presented by Tamara Rezk – INDES project - INRIA Joint work with: Cédric.
CSE341: Programming Languages Lecture 11 Type Inference Dan Grossman Winter 2013.
INF5110: Mandatory Exercise 2 Eyvind W. Axelsen @eyvindwa Slides are partly based on.
Crowfoot: a verifier for higher order store programs Billiejoe (Nathaniel) Charlton Ben Horsfall Bernhard Reus University of Sussex VMCAI 2012.
GRADUAL TYPING EMBEDDED SECURELY IN JAVASCRIPT Aseem Rastogi University of Maryland, College Park Joint Work With: Nikhil Swamy, Cédric Fournet, Karthikeyan.
Software Engineering Prof. Dr. Bertrand Meyer March 2007 – June 2007 Chair of Software Engineering Static program checking and verification Slides: Based.
Computer Science Detecting Memory Access Errors via Illegal Write Monitoring Ongoing Research by Emre Can Sezer.
CS 363 Comparative Programming Languages Semantics.
Typing Local Control and State Using Flow Analysis Arjun Guha, Claudiu Saftoiu, and Shriram Krishnamurthi 1.
A Universe-Type-Based Verification Technique for Mutable Static Fields and Methods Alexander J Summers Sophia Drossopoulou Imperial College London Peter.
Reasoning about programs March CSE 403, Winter 2011, Brun.
CS536 Semantic Analysis Introduction with Emphasis on Name Analysis 1.
ANU COMP2110 Software Design in 2003 Lecture 10Slide 1 COMP2110 Software Design in 2004 Lecture 12 Documenting Detailed Design How to write down detailed.
Fall 2008Programming Development Techniques 1 Topic 17 Assignment, Local State, and the Environment Model of Evaluation Section 3.1 & 3.2.
Semantic Analysis II Type Checking EECS 483 – Lecture 12 University of Michigan Wednesday, October 18, 2006.
Advanced Functional Programming Tim Sheard 1 Lecture 17 Advanced Functional Programming Tim Sheard Oregon Graduate Institute of Science & Technology Lecture:
1 Static Contract Checking for Haskell Dana N. Xu University of Cambridge Joint work with Simon Peyton Jones Microsoft Research Cambridge Koen Claessen.
CSE 130 : Winter 2009 Programming Languages Lecture 11: What’s in a Name ?
COMP 412, FALL Type Systems II C OMP 412 Rice University Houston, Texas Fall 2000 Copyright 2000, Robert Cartwright, all rights reserved. Students.
Shifting the Blame A blame calculus with delimited control Taro Sekiyama* Atsushi Igarashi Soichiro Ueda Kyoto University Gradual typing.
Prof. Necula CS 164 Lecture 171 Operational Semantics of Cool ICOM 4029 Lecture 10.
CS5205Semantics1 CS5205: Foundation in Programming Languages Semantics Static Semantics Dynamic Semantics Operational Semantics Big-step Small-Step Denotational.
The Ins and Outs of Gradual Type Inference Avik Chaudhuri Basil Hosmer Adobe Systems Aseem Rastogi Stony Brook University.
Heath Carroll Bill Hanczaryk Rich Porter.  A Theory of Type Polymorphism in Programming ◦ Robin Milner (1977)  Milner credited with introducing the.
CSE341: Programming Languages Lecture 11 Type Inference
Context-Sensitive Analysis
Matching Logic An Alternative to Hoare/Floyd Logic
Stateful Manifest Contracts
TS*: Taming the Un-typed Adversary in JavaScript
CSE341: Programming Languages Lecture 11 Type Inference
CSE341: Programming Languages Lecture 11 Type Inference
CSE341: Programming Languages Lecture 11 Type Inference
CSE341: Programming Languages Lecture 11 Type Inference
CSE341: Programming Languages Lecture 11 Type Inference
Static Contract Checking for Haskell
Reasoning with Types.
Presentation transcript:

Taming JavaScript with F* Nikhil Swamy Microsoft Research

Computers of all shapes and sizes … … Everywhere!

But … “hello” + 17 ~> “hello17” ‘0’ == false ~> true {f:0}.g ~> undefined ' \t\r\n ' == 0 ~> true … huh?!

Does this assertion always succeed? function wrap (rawSend){ var whitelist = [' ' ; return function (target, msg) { if (whitelist[target]) rawSend (target, msg); else throw("Rejected"); } Object.prototype[“evil.com”] = true If the context adds a field to Object.prototype, it can circumvent the whiteList check in wrap(rawSend) INSECURE! function foo(x) { return x + 1; } function bar(x) { assert (foo(0)==1); } foo = function (x) { return x; } Not if you can change foo Does wrap intercept all sends with a whitelist check? REASONING ABOUT JAVASCRIPT IS HARD!

An ML-like programming language with an SMT-based type system for program verification Enter F* … Juan Chen Cédric Fournet Ben Livshits Pierre Dagand Cole Schlesinger Joel Weinberger Pierre-Yves Strub

function foo(x) { return x + 1; } function bar(x) { assert (foo(0)==1); } prog.js let foo = mkFun (fun x -> …) in update global “foo” foo; let bar = mkFun (fun x -> … assert … ) in … prog.fst Translate Annotate invariants Invariants Translate Verify 1. Static assertion checking of JavaScript source Verifying higher-order programs with the Dijkstra monad; PLDI 2013

2. A fully abstract compiler from F* to JavaScript let foo x = x + 1 let bar = assert (foo 0 = 1) prog.fst Fully abstract compilation to JavaScript; POPL 2013 Guaranteed to satisfy all properties of prog.fst, by construction function () { function foo(x) { return x + 1; }; assert (foo(0)==1); } () prog.js Compile

If you must program in JavaScript: F* can statically analyze your code for safety Others tools can help too: DJS by Chugh et al; Gatekeeper by Livshits et al.; … Otherwise, program in a nicer source language and compile safely to JS

JavaScript Semantics?

JS*: A semantics of JavaScript within F* JS2JS* (x={f:’hello’}, x.f) open JSStar update global (Str “x”) (objlit [(“f”, Str “hello”)]); select (select global (Str “x”)) (Str “f”) module JSStar type dyn = Str : … | … val select: o:dyn -> f:dyn -> … val update: o:dyn -> f:dyn -> v:dyn -> … val objlit: list (string * dyn) -> … JS2JS* based on LambdaJS; Guha et al.; ECOOP 2010 a.js a.js.fst JSStar.fst JS*: An instance of F*, where all free variables are defined by the module JSStar

function foo(x) { this.g = x.f + 1; } foo({f:0}); foo=17; let foo = fun this args -> let x = select args (Str “0”) in update this (Str “g”) (plus (select x (Str “f”)) (Num 1.0)) in update glob (Str “foo”) (Fun foo); let args = objLit [(Str “0”, objLit [(Str “f”, Num 0.0)])] in apply (select glob (Str “foo”)) glob args; update glob (Str “foo”) (Num 17.0) JS JS* JS2JS* The translation of every sub-term has type dyn in JS* Named functions are stored in the enclosing object Function calls involve lookups in a dynamically typed higher-order store Store is subject to arbitrary updates > > > > > >

module JSStar type dyn = | Num : float -> dyn | Str : string -> dyn | Obj : ref (map string dyn) -> dyn … | Fun : (dyn -> dyn -> dyn) -> dyn

module JSStar type dyn = | Num : float -> d:dyn{TypeOf d = float} | Str : string -> d:dyn{TypeOf d = string} | Obj : ref (map string dyn) -> d:dyn{TypeOf d = object} … | Fun : (x:dyn -> y:dyn -> ST dyn (WP x y)) -> d:dyn{TypeOf d = Function WP} //Refined type dyn Refinement formula recovers static type information Refinement for a function records the weakest pre-condition of the function Dijkstra State Monad The type of a computation that diverges or produces a dyn result satisfying Post when run in a heap satisfying WP x y Post

module JSStar type dyn = | Num : float -> d:dyn{TypeOf d = float} | Str : string -> d:dyn{TypeOf d = string} | Obj : ref (map string dyn) -> d:dyn{TypeOf d = object} … | Fun : (x:dyn -> y:dyn -> ST dyn (WP x y)) -> d:dyn{TypeOf d = Function WP} val select: o:dyn -> f:dyn -> ST dyn (Requires (\h. TypeOf o = object /\ HasField h o f)) (Ensures (\res h0 h1. h0=h1 /\ res=SelectField h0 o f)) let select o f = //traverse prototype chains etc. val update: o:dyn -> f:dyn -> v:dyn -> ST dyn (Requires (\h. TypeOf o = object)) (Ensures (\res h0 h1. h1=UpdateField h0 o f b /\ res=Undef) let update o f v = //traverse prototype chains etc. … //Refined type dyn

function foo(x) { return x + 1; } function bar(x) { assert (foo(0)==1); } prog.js let foo = mkFun (fun x -> …) in update global “foo” foo; let bar = mkFun (fun x -> … assert … ) in … prog.fst JS2JS* Annotate invariants Invariants Verifying higher-order programs with the Dijkstra monad; PLDI 2013 module JSStar val update:… val apply: … Computes verification conditions Z3 Discharges proof obligations

JSStar Verified for functional correctness Verified for absence of runtime errors

Writing JS functions that have trivial pre-conditions is really hard! function wrap (rawSend){ var whitelist = [' ' ; return function (target, msg) { if (whitelist[target]) rawSend (target, msg); else throw("Rejected"); } Object.prototype[“evil.com”] = true function foo(x) { return x + 1; } function bar(x) { assert (foo(0)==1); } Requires \h. TypeOf h[glob[“foo”]]=Function WP … Ensures … Pre-condition to ensure the correctness of wrap? Ok, but what about the context?

What if you could instead write wrap in ML? (Or your favorite high-level language) And we compiled it to JavaScript for you let wrap rawSend = let whitelist = [“ “ in let newSend target msg = if List.contains whitelist target then rawSend target msg else () in newSend //Obviously correct!

Script# Pit Fay WhaleSong … That seems to be the way things are going …

WebPage = { doStuff : function () { … } } … module WebPage = struct type t = … let doStuff … end WebPage.html WebPage.ml Interactions between compiled ML code and JS can be problematic

let wrap rawSend = let whiteList = [" " in fun target msg -> if mem target whiteList then rawSend target msg else failwith "Rejected" function wrap (rawSend){ var whitelist = [' ' ; return function (target, msg) { if (whitelist[target]) rawSend (target, msg); else throw("Rejected"); } Compile naively Object.prototype[“evil.com”] = true If the context adds a field to Object.prototype, it can circumvent the whiteList check in wrap(rawSend) INSECURE!

Allows a programmer to reason in source semantics Emits JavaScript that behaves like the source program In ALL JavaScript contexts Need a compiler that: Intuitively, this should be hard because JavaScript contexts can do more than (say) ML contexts Prototype poisoning getters/setters Implicit conversions Functions as objects An unusual calling convention Function.toString arguments.callee.caller (new Error()).stack with eval … ??

A fully abstract compiler from F* to JavaScript Where for a language L : Full abstraction is the ideal property for a translation:

js*: An instance of f* let id (x:string) = x in id “hello” function () { var id = function (x) { return x; }; return id(“hello”); } () f*JavaScript open JSStar apply Null (mkFun “init” (fun me _ _ -> let id = mkLocal () in set me id “0” (mkFun …); apply me (select me id “0”) (mkArgs [Str “hello”])) window (mkArgs []) module JSStar type dyn = … let apply : … let mkFun : … let mkLocal : … … Compiler implementation Formal translation Lemma: Given any JavaScript program, our semantics produces a well-typed js* program JS2JS*

let id (x:string) = x in id “hello” open JSStar apply Null (mkFun “init” (fun …) window (mkArgs []) module JSStar type dyn = Null | Str of string | … let apply : … let mkFun : … let mkLocal : … … Formal translation “hello” open JSStar Str “hello” Formal translation Source f*: Target js*:

Proof technique leveraging f* (a) Type-based verification of key invariants Heap shape invariant Heap separation invariant Type preservation lemma Weak forward simulation module JSStar type dyn = | Num : float -> d:dyn{TypeOf d = float} | Str : string -> d:dyn{TypeOf d = string} | Obj : ref (map string dyn) -> d:dyn{TypeOf d = object} … | Fun : (x:dyn -> y:dyn -> ST dyn (WP x y)) -> d:dyn{TypeOf d = Function WP} val select: o:dyn -> f:dyn -> ST dyn (Requires (\h. TypeOf o = object /\ HasField h o f)) (Ensures (\res h0 h1. h0=h1 /\ res=SelectField h0 o f)) val update: o:dyn -> f:dyn -> v:dyn -> ST dyn (Requires (\h. TypeOf o = object)) (Ensures (\res h0 h1. h1=UpdateField h0 o f b /\ res=Undef) …

Proof technique leveraging f* (b) A new applicative bisimulation for contextual equivalence Supports higher-order functions, mutable state, exceptions, divergence, fatal errors – Same bisimulation applies to both source and target, since both are just instances of f* Theorem: Applicative bisimilarity (the largest bisimulation) is sound and complete w.r.t contextual equivalence Theorem (equivalence preservation): Formal translation of a bisimilar source f* configurations produces bisimilar js* configurations. Theorem (equivalence reflection): If the formal translation of any pair of source f* configurations produces bisimilar js* configurations, then source f* configurations are bisimilar.

Structure of the translation Two phases 1. A compositional “light translation” 2. Type-directed defensive wrapping

let id (x:string) = x in id “hello” var id = function (x) { return x; } id(“hello”) let id = ref Undefined in let f = fun me this args -> lookup !args “0” in id := mkFun f; apply !id window (mkArgs [(“0”, “hello”)]) Light translation Syntactically simple Semantically complex! Heavy use of mutation Higher-order store Functions are objects too Unusual calling convention …

Interacting with a JS context fun (b:bool) -> b function (b) { return b; } fun b -> function (b) { if b then true return b ? true : false; else false } Distinguishing JS context: function (f) {return (0 === f(0));} Light translation Light translation

Phase 2: Type-directed defensive wrappers: ↓t : t -> Un ↑t : Un -> t Compile(e:t) = ↓t ([[e]]) : Un Un : “unconfidential/untrusted” values that can be disclosed to the context or provided by the context

Defensive wrappers: ↑t : Un -> t ↓t : t -> Un Enforcing a strict heap separation Down wrappers export values to the context: ↓bool = function(b){return b;} ↓(a * b) = function(p){return {0:↓a(p[“0”]), 1:↓b(p[“1”]);} ↓(a -> b) = function(f){return function(x) {return ↓b(f(↑a(x)));};} Up wrappers import values from the context: ↑bool = function(b){return b?true:false;} ↑(a * b) = function(p){return {0: ↑a(p[“0”]), 1:↑b(p[“1”]);} ↑(a -> b) = …

= (, j:[[t]] ) = ( ‘ ‘, j’:[[t]] ) Many steps of js* Some properties of the translation expressed using the types of F* partially mechanized using the F* typechecker [[(, e:t )]] Ref cells Types preserved Heap separation and shape invariant 1-step of source f* [[(, e’:t )]] Ref cells’ UnStub’Fun’RefImmutUnStubFunRefImmut

Wrappers secure interactions with the context fun (b:bool) -> b ↓(bool -> bool) (function (b) { return b; }) fun b -> ↓(bool -> bool) if b then true (function (b) { else false return b ? true : false; }) compile

(fun b f -> f() && b) true fun f -> f() function(b) { return function(f) { return (f() && b);}; }(true); function(f) {return f();} function(g) { return g(function() { arguments.callee.caller.arguments[0] = false; return true;}); } JS callbacks can walk the stack Light translation Light translation

Callback “stubs” prevent stack walks ↑(a -> b) = function (f) { return function (x) { var z = ↓a(x); var y = undefined; function stub(b) { if (b) { stub(false); } else { y = ↑b(f(z)); } } stub(true); return y; }; } See online paper for details

Limitations Side channels – Full abstraction can be broken with resource exhaustion/timing attacks Cannot import polymorphic functions Temporary limitations – Context can use exceptions But not yet source programs – Implementation supports polymorphism But not in our formalism yet

Demo

JS dialects / sub-languages class Greeter { who: string; constructor (w:string) { this.who=w; } greet() { return “Thank you, “ +this.who; } new Greeter(“HCSS!").greet(); Static (gradual) typing Better IDE support Verification more feasible Script# Pit Fay Whale Song Use our wrappers for heap separation Allow your programmers to think in source semantics! JS as a compiler target

We provide solutions for programmers who: … must write JavaScript code directly … can generate JS from a language with a cleaner semantics JavaScript: Not so bad after all … at least as a compilation target

Experiments A mini-ML compiler bootstrapped in JavaScript – ~1.5 seconds to bootstrap in F#/.NET – ~3 seconds to bootstrap in IE 10 Several small security examples – Secure local storage, API monitoring, etc. Online demo and “full-abstraction game”:

Anyone for ?