Authors Arjun Guha Jane Tangen Jean-Baptiste Jeannin Rachit Nigam Rian Shambaugh
License CC-BY-3.0
Fission: Secure Dynamic Code-Splitting for JavaScript∗ Arjun Guha1 , Jean-Baptiste Jeannin2 , Rachit Nigam3 , Rian Shambaugh4 , and Jane Tangen5 1 University of Massachusetts Amherst, Amherst, MA, USA 2 Samsung Research America, Mountain View, CA, USA 3 University of Massachusetts Amherst, Amherst, MA, USA 4 University of Massachusetts Amherst, Amherst, MA, USA 5 University of Massachusetts Amherst, Amherst, MA, USA Abstract Traditional web programming involves the creation of two distinct programs: a client-side front- end, a server-side back-end, and a lot of communications boilerplate. An alternative approach is to use a tierless programming model, where a single program describes the behavior of both the client and the server, and the runtime system takes care of communication. Unfortunately, this usually entails adopting a new language and thus abandoning well-worn libraries and web programming tools. In this paper, we present our ongoing work on Fission, a platform that uses dynamic tier- splitting and dynamic information flow control to transparently run a single JavaScript program across the client and server. Although static tier-splitting has been studied before, our focus on dynamic approaches presents several new challenges and opportunities. For example, Fission supports characteristic JavaScript features such as eval and sophisticated JavaScript libraries like React. Therefore, programmers can reason about the integrity and confidentiality of information while continuing to use common libraries and programming patterns. Moreover, by unifying the client and server into a single program, Fission allows language-based tools, like type systems and IDEs, to manipulate complete web applications. To illustrate, we use TypeScript to ensure that client-server communication does not go wrong. 1998 ACM Subject Classification D.3.2. Multiparadigm Languages Keywords and phrases JavaScript, information flow control Digital Object Identifier 10.4230/LIPIcs.SNAPL.2017.5 1 Introduction Two decades after the introduction of JavaScript, web application security remains a chal- lenging problem that continues to grow in significance. For example, over the past three years, the CVE database has accumulated over 2,500 cross-site scripting (XSS) vulnerabilities in popular open-source web technologies, such as Wordpress and Ruby on Rails [58, 20]. Major technology companies, such as Google, Facebook, and Microsoft regularly award bug bounties worth several thousand dollars to white-hat hackers who find vulnerabilities in their websites [25, 22, 10]. These kinds of vulnerabilities have also been making headline ∗ This work is supported by the U.S. National Science Foundation under grants CNS-1413985 and CCF-1408745. © Arjun Guha, Jean-Baptiste Jeannin, Rachit Nigam, Rian Shambaugh, and Jane Tangen; licensed under Creative Commons License CC-BY 2nd Summit on Advances in Programming Languages (SNAPL 2017). Editors: Benjamin S. Lerner, Rastislav Bodík, and Shriram Krishnamurthi; Article No. 5; pp. 5:1–5:13 Leibniz International Proceedings in Informatics Schloss Dagstuhl – Leibniz-Zentrum für Informatik, Dagstuhl Publishing, Germany 5:2 Fission: Secure Dynamic Code-Splitting for JavaScript news, since hackers exploited a web-based SQL injection vulnerability to gain access to the computer systems of the U.S. Election Assistance Commission [42]. Existing Approaches. The programming languages research community has addressed the web application security problem in several different ways. For example, there is a large body of work on type systems [36, 14, 50, 35, 29, 47, 30, 5, 55, 16, 56, 57, 11] and program analyses [37, 6, 27, 15, 26, 54, 33] for JavaScript. Since many security vulnerabilities are caused by JavaScript’s confounding dynamic semantics [38, 23, 46, 28, 39, 49, 45, 44, 9], a security-conscious programmer could leverage a type system or program analysis to avoid JavaScript’s pitfalls. Naturally, static disciplines impose restrictions: it is difficult for tools to reason statically about dynamically-loaded code (eval) and other characteristic features of JavaScript. Moreover, client-side JavaScript is only half of any web application. Many security vulnerabilities occur on the server, where a variety of languages, such as PHP, Perl, Python, Ruby, and even JavaScript (using NodeJS) are in use. These other scripting languages have also been subjected to type systems and static analyses [24, 4]. However, to formally reason about the behavior and security of a web application, a tool has to consider the client-side and server-side programs together. Reasoning about multi-lingual systems is a challenging problem that is an active area of research [1, 40, 43].1 An alternative approach is to abandon the traditional web programming model and use a tierless programming language, where a single program written in a single programming language describes the behavior of the client and the server. For example, Links [18] and Ur/Web [12] provide a unified language for programming the client, server, and the database. SELinks enhances the Links model with statically-checked, label-based security policies [19]. In contrast, Swift [13] automatically partitions security-typed programs written in JIF [32] into client-side and server-side components. Tierless languages thus enable a variety of creative security solutions, but their defining characteristic is that the entire application is written in a single language, which allows programmers and developer tools to reason algebraically about their code. JavaScript Is Hard To Let Go. Unfortunately, a key shortcoming of the aforementioned tierless languages is that they are not JavaScript, thus they abandon the large and vibrant JavaScript ecosystem. For example, web programmers have grown dependent on libraries like jQuery to build cross-platform web applications; modern applications use frameworks like Facebook React, which bring elements of reactive programming to the mainstream; and language extensions like JSX that allow programmers to use XML notation within JavaScript; and tools like TypeScript bring a modicum of safety to everyday JavaScript code, despite deliberately abandoning soundness. If we ask programmers to use a newly designed language, we are asking them to give up this ecosystem of libraries and language-based tools. Our Approach. In this paper, we present Fission, a new approach to web application security that is not only compatible with the JavaScript ecosystem, but can even make existing JavaScript tools more effective. Fission allows web applications to be written as a single JavaScript program and uses dynamic information flow control and dynamic tier- splitting to automatically and securely split it into client-side and server-side code. Although 1 Even if JavaScript is also used on the server, the client and server operate as two independent programs that communicate over HTTP. Therefore, one cannot reason about these programs using only the semantics of JavaScript. A. Guha, J. B. Jeannin, R. Nigam, R. Shambaugh, and J. Tangen 5:3 static information flow control and tier-splitting has been explored before, we show that doing both of these dynamically has several advantages: By eschewing static approaches, Fission places no restrictions on JavaScript. Fission is fully compatible with ECMAScript 5, including characteristic JavaScript features, such as prototype inheritance and eval. We apply Fission to several large programs that use ECMAScript 6 (via Babel), JSX, and React on the client and NodeJS on the server. By fusing the client-side and server-side into a single program, Fission lets us delete a lot of brittle serialization and communication boilerplate code. Fission’s dynamic tier-splitting allows the client and server to share code. In particular, certain higher-order function can be evaluated on either the client or the server, based on the context in which they are applied. Beyond Security. Fission’s information flow control can help programmers reason about the confidentiality and integrity of data. However, Fission’s tierless design provides additional benefits. A shortcoming of the two-tier, web programming model is that it limits our ability to reason linguistically about program behavior. HTTP requests and web servers are an extra-linguistic feature and aren’t part of the semantics of JavaScript. One way to address this issue is to add new language features to JavaScript [53]. However, since Fission makes web requests completely transparent, it allows us to reason about our code using just the semantics of JavaScript. Although it is rare for programmers to reason about web programs, there are several tools that do reason about JavaScript and these can be applied to Fission programs with minimal effort: We use Fission to develop server-side APIs (e.g., file I/O) for Elm [21]. Elm is a wonderful alternative to JavaScript, but without Fission, Elm programmers have to step outside the language to get any work done on the server. Furthermore, Fission could also be used with other languages that compile to JavaScript. We use Fission and TypeScript to write statically-typed web applications, where types ensure that client-server communication does not go wrong. Finally, we are able to use IDE features, such as refactoring tools, to consistently transform the client-side and server-side components of a program. All these applications are possible because Fission faithfully implements JavaScript instead of requiring an entirely new programming language. Moreover, it is precisely because we do not design a new tierless language that Fission presents several new challenges. First, we introduce the Fission programming model in more depth. 2 A Fission Example Figure 1 shows a two-tier program where both client and server are written in JavaScript. The purpose of this program is to display files stored on the server. When the user enters a filename and clicks “Load”, the client sends a request to the server. The server either responds with the file contents or fails gracefully if the file is unreadable. Even in this trivial program, several shortcomings are apparent. First, the control-flow of the program is disjointed and bounces back and forth between the client and the server (indicated by the arrows in the figure). Second, about half the code is boilerplate needed to make requests, setup request handlers, and serialize data (highlighted in red). Finally, since the client and server are two logically distinct programs, it is difficult for programmers and tools to reason SNAPL 2017 5:4 Fission: Secure Dynamic Code-Splitting for JavaScript < input id = ’ name ’ > var express = require(’express’); < button onclick = ’ loadHandler ’ > Load </ button > var app = express(); < div id = ’ contents ’ > </ div > app.use(require(’body-parser’).text()); function loadHandler () { app.get(’/index.html’, function (req, res) { var req = new XMLHttpRequest(); res.sendFile(’index.html’); req.open(’GET’, ’/load’); }); req . onload = function () { var rng = document . createRange (); app.get(’/read’, function(req, res) { rng . s e l e c t N o d e C o n t e n t s ( contents ) try { . del eteConte nts (); var name = req.body.toString(); var resp = JSON.parse(xhr.responseText); var b = fs . readFileSync ( name , var txt = resp . ok ? resp . body : " Error "; ’ utf8 ’); var elt = document . createElement ( ’ div ’); var r = { ok : true , body : b }; elt . appendChild ( res.send(JSON.stringify(r)); document . createTe xtNode ( txt )); } catch ( e ) { contents . appendChild ( elt ); res.send(JSON.stringify({ ok; false })); } } req.send(name.value); } } Figure 1 A canonical two-tier web application. < input id = ’ name ’ > < button onclick = ’ loadHandler ’ > Load </ button > < div id = ’ contents ’ > </ div > function loadHandler () { var rng = document . createRange (); rng . s e l e c t N o d e C o n t e n t s ( contents ). d eleteCon tents (); var txt ; try { txt = declassify ( fs . readFileSync ( name . value )); } catch ( e ) { txt = " Error "; } var elt = document . createElement ( ’ div ’); elt . appendChild ( document . createT extNode ( txt )); contents . appendChild ( elt ); } Figure 2 A tierless version of Fig. 1. about their behavior. JavaScript tools cannot catch the trivial bug in the figure: the client requests /load, but the server has a handler for /read. Figure 2 refactors the program to use Fission, which addresses the problems listed above. First, the boilerplate that was highlighted in the previous figure has been eliminated, since Fission handles serialization transparently. Second, the control-flow of the program is more natural since a single function can use both client and server APIs. Finally, since we no longer have two programs that explicitly communicate over HTTP, the bug in the previous program has been eliminated. Moreover, we can now leverage JavaScript tools to manipulate the entire program without breaking client/server consistency. For example, we could use an IDE to rename the txt variable which is written on the server but read on the client. With Fission, JavaScript developer tools can work on the whole program and aren’t limited to only the client-side code. Attacker Model. Fission adopts the standard web attacker model [2] and assumes that an attacker can compromise the client and the network. Therefore, all values sent to the client are public to the attacker and all values received from the client are untrusted. Information Flow Control. Fission uses dynamic information flow control, to securely partition code and data across the client and server. To a first approximation, all Fission values have two tags. A secrecy tag indicates whether a value is secret or public and an integrity tag indicates whether a value is trusted or untrusted. Therefore, Fission incorporates its attacker model as follows: Fission assumes that all client-side functions (i.e., all DOM A. Guha, J. B. Jeannin, R. Nigam, R. Shambaugh, and J. Tangen 5:5 var found = ’ Looking ... ’; var txt = fs . readFileSync ( ’/ etc / passwd ’ , ’ utf8 ’); if ( txt . indexOf ( ’ alice ’) >= 0) { found = true ; } else { found = false ; } Figure 3 Indirect information flow. APIs) produce public, untrusted values and that all server-side functions (i.e., all NodeJS APIs) produce secret, trusted values.2 Moreover, Fission will not send secret values to the client. Therefore, when a program needs to write a secret value to the client, it needs to be declassified. Untrusted values from the client can be endorsed in a similar way. Fission asks programmers not to think about requests, responses, and serialization, but to think about the provenance of their data. This is not a new idea, but our experience with Fission shows that dynamic information flow control and dynamic tier-splitting is a powerful combination. Moreover, since Fission faithfully implements JavaScript, it supports several existing JavaScript libraries and tools with no changes required. The Last Event Handler. Readers who enjoy functional reactive programming may be unhappy that the Fission code in Fig. 2 has one imperative event handler left. Instead of rehashing reactive programming for JavaScript, it is easy to reuse an existing JavaScript reactive programming library with Fission. Alternatively, the program could be rewritten in a language like Elm, using Fission to add support for transparent file I/O. Overview. The rest of this paper summarizes Fission’s technical approach, discusses some of the language design and implementation challenges we had to address, and some open research questions. 3 Faceted Execution Faceted execution [7] is a form of termination-insensitive dynamic information flow control (IFC). The key idea in faceted execution is a faceted value (or facet for short), which is a pair of two values, where one is secret and the other is public. Which value is observed depends on the permissions of the observer. For example, when writing to the client, a facet is projected to its public component because all values on the client are visible to the attacker. Conversely, when reading from a secret file on the server, we create a facet where the private component has the file contents and the public component is a special unreadable value (⊥). Let’s consider a concrete example that has an indirect information flow. The program in Fig. 3 reads the user database from a server, tests if the account alice exists, and then sets the variable found to true or false. Since readFileSync is a NodeJS function, the variable txt holds a facet, where the secret component is the file contents and the public component is ⊥, thus the client cannot directly read the file. Since the expression in the conditional uses the txt variable, the value of the conditional is a facet too, where the secret component is a boolean and the public component is ⊥. Therefore, the assignment to found is affected by a secret value, even though no secret is directly written to found. Fortunately, faceted execution updates found to hold a facet, where the secret component is the boolean and 2 A programmer can write more sophisticated, multi-principal policies, but these are reasonable defaults. SNAPL 2017 5:6 Fission: Secure Dynamic Code-Splitting for JavaScript the public component is the original public value (the string ’Looking ...’). Therefore, the server can observe the boolean which indicates whether the user alice exists, whereas the client sees the original value, thus cannot determine which branch was taken, unless the program is modified to declassify the value. Therefore, to implement faceted execution, the control operators and primitive operations of JavaScript have to be lifted to manipulate faceted values appropriately. Facets can be nested and labeled to implement both confidentiality and integrity policies with several principals. Although Fission supports all these features, a typical Fission program only needs to reason about one principal, the server, and the programmer only needs to reason about whether values originated on the client or the server. Cooperating Faceted Evaluators. A distinguishing characteristic of Fission is that it requires two faceted evaluators – one on the client and the other on the server – to cooperatively evaluate the program. Moreover, since the attacker model entails that the server-side evaluator cannot trust the client-side evaluator in any way, the server-side evaluator can neither send secrets to the client nor trust any information sent by the client. Prior work on faceted execution has been based on a big-step semantics, which lends itself to a simple, direct-style interpreter. However, we had to develop a small-step faceted semantics with an explicit stack3 because a context-switch requires an evaluator to examine its own stack, serialize it, and send it to the other evaluator. For example, if the server-side evaluator is running and the current stack frame is an application of a client-side function, at least that frame has to be serialized and transferred to the client. It would be unsafe for the server to transfer stack frames that contain secrets to the client. So, what should happen if program applies a client-side function to a faceted argument that contain secrets? Since the Fission programming model assumes that client-side function only consume public values, a well-behaved client would simply discard the secret part of the argument and only use the public part. Instead of assuming that the client is well-behaved, the Fission server can instead project stack frames to only contain public values before transferring them to the client. This does not change the behavior of a well-behaved client, but prevents an attacker from observing secret values. Fission follows a similar approach with client-side state. The Fission programming model assumes that a web page’s title, URL, cookies, etc. are always public. Therefore, when client-side state is updated to a new value, that value is projected to its public component before being transferred to the client. Compilation and Taint Tracking. Our current implementation of Fission is an interpreter that is fast enough for interactive web pages. However, compiling Fission (or any faceted language) is challenging because each side of a facet may (or may not) follow a different branch. However, recent work [51] shows that faceted execution can be applied to taint tracking and that faceted taint tracking can be compiled in a relatively straightforward manner. Therefore, in situations where implicit flows are not a concern, a taint-tracking variant of Fission may be faster and easier to use. 4 Tier Splitting The Fission programming model lends itself to several different implementations with a variety of tradeoffs. In particular, since the transfer of control between client and server is transparent to the program, tier splitting can be implemented in several ways. 3 In essence, a faceted CEK machine. A. Guha, J. B. Jeannin, R. Nigam, R. Shambaugh, and J. Tangen 5:7 Static Splitting. Although JavaScript is not statically typed, it should be possible to statically place expressions on the client or server. In brief, we could build a static control flow and data flow graph of the program, determine which expressions compute high-integrity values or consume secret values and ensure that these expressions are evaluated on the server. Swift [13] uses a richer variant of this approach, along with support for replicated data to keep the user interface responsive. We have yet to evaluate this approach in Fission, but we suspect that it may be too conservative for modern JavaScript that makes extensive use of higher-order functions. Even if programmers don’t use higher-order functions themselves, they are generated by tools like Babel to implement modules. In these situations, a context- insensitive control flow graph may force too much code to needlessly run on the server. In addition, Fission supports eval, which gives fully static methods a lot of trouble. Dynamic Splitting. In Fission, we tier-split the program dynamically because it produces better results for programs that use higher-order functions. The key idea is that the server can dynamically transfer control to the client (or vice versa) by transferring a prefix of the stack. However, since data sent to the client cannot contain secrets and data returned from the client cannot be trusted, the server cannot send an arbitrary portion of the stack. We use a lightweight, conservative analysis to determine which stack frames can be sent to the client without violating any of these requirements. For example, suppose a program runs an expensive computation and displays its result on the client. var x = fibonacci (50); alert ( x ) fs . writeFile ( ’ result . txt ’ , x ); Since the value is not needed on the server, the expression can be evaluated entirely on the client, as long as the computation doesn’t need to read secrets or update trusted values. However, if the value is also stored on the server, the computation needs to be performed on the server too. Dynamic tier-splitting is particularly effective when a program uses higher-order functions that cannot be statically placed on either the client or the server. Consider the canonical apply higher-order function, which can be applied to either a function that must run on the client or a function that must run on the server. function app (f , x ) { return f ( x ); } app ( fs . readFileSync , ’ secret . txt ’); app ( window . alert , ’ hello ’); Therefore, we cannot statically determine where app(x) should be evaluated without con- sidering the context where the evaluation occurs, and context-sensitive static analyses are very expensive. However, by examining the dynamic context, Fission can find a sequence of stack frames that do not read secrets, do not update trusted values, and do not execute operations like declassification and endorsement that have to be performed in a trusted context. Stack frames that meet these requirements can be evaluated on the client. These are broad requirements that allow a variety of tier-splitting mechanisms. We’ve developed a lightweight, conservative analysis that is effective on our benchmark programs, but it is straightforward to write contorted code that defeats the analysis and causes unnecessary context switching. A more precise analysis may be better at tier-splitting complicated code, but also have a longer running time. There is a large space of tier-splitting policies that can be explored. SNAPL 2017 5:8 Fission: Secure Dynamic Code-Splitting for JavaScript 5 JavaScript and Interoperability Fission supports the ECMAScript 5.1 language standard, which is a close approximation of the JavaScript currently supported by major browsers. Unfortunately, ECMAScript is a fairly complicated language that includes getters and setters, object-oriented meta-programming features, and two language modes, in addition to well-known JavaScript pain-points, such as prototype inheritance, dynamic code-loading with eval, and more. Fission tackles this complexity by compiling JavaScript to a core language based on λJS [28] and S5 [45]. Fission’s core language has additional features to support faceted execution as described above. Let us now highlight Fission’s implementation of eval, which is deeply affected by the attacker model. Note that Fission cannot implement eval by directly calling JavaScript’s built-in eval function. If it did, the evaluated JavaScript code would not be able to interoperate with Fission’s faceted JavaScript. Instead, Fission’s implementation of eval builds a JavaScript AST, compiles it to a core language expression, and evaluates it using the Fission interpreter. If the call to eval is made in a trusted context, the JavaScript AST may even have sensitive operations like declassification and endorsement. Fission already ensures that the client is untrusted, therefore, a trusted call to eval may only occur on the server. In contrast, an untrusted call to eval may occur on either the client or the server. However, the code generated by an untrusted eval can neither neither access secret values nor endorse/declassify values. Notably, Fission does not need any additional mechanism to ensure that these properties hold when untrusted strings are evaluated. The same mechanisms in Fission that mediate interactions between the client and the server also ensure that untrusted strings can be safely evaluated. Although web programming best practices eschew using eval, it is still a commonly used construct [49], which is why put in the effort to support it. Fission is carefully designed to support JavaScript’s event-driven programming model. Therefore, a server-side event handler can transfer control to the client and vice versa. This requires full bidirectional communication, which Fission builds atop WebSockets. Moreover, if two events occur simultaneously on the client and the server, Fission serializes them to preserve JavaScript’s single-threaded semantics. The current implementation of Fission suspends the client when the server is executing and vice versa, which is a reasonable default. However, there are scenarios where it is desirable to run client and server code in parallel. Other tierless languages expose server-side concurrency using libraries or special linguistic constructs [12, 18]. For the moment, we are evaluating Fission on existing NodeJS and Elm applications that do not require concurrency. 6 Applications React-based Web applications. We have used Fission to refactor a handful of applications written for a final project in an undergraduate web programming class. All these applications use JavaScript on the client and NodeJS on the server, so refactoring involved directly calling request handlers at request sites (instead of making HTTP requests) and deleting serialization code. In addition, we had to insert declassification and endorsement operations, which is easy to do when server-side code is already factored into separate functions: we endorse all arguments and declassify the result. These applications have several hundred to two thousand lines of student-written code. However, all applications use Facebook React and several other JavaScript libraries. When they are linked together using Babel, each application has over 50,000 lines of code. Therefore, these are non-trivial examples that truly exercise the implementation. The Fission interpreter, which is written in JavaScript, takes a few seconds to load these programs, which start instantly without Fission. However, since A. Guha, J. B. Jeannin, R. Nigam, R. Shambaugh, and J. Tangen 5:9 these are interactive programs that are not compute-heavy, the slowdown is not noticeable when they are in use. Elm. For readers who dislike JavaScript and would rather program in a statically-typed, ML-based language, we have used Fission to implement an Elm module that adds support for reading and writing files on the server. The library requires about five lines of code for each NodeJS function exported to Elm and leverages Fission to automatically context switch between the client and server. It would be straightforward to add wrappers for more NodeJS functions to enable pure Elm applications to seamlessly run on the client and server. TypeScript and IDEs. There exist canonical TypeScript type definitions for both the NodeJS API and the Web browser DOM API. It usually does not make sense to import both type definitions in a single program, but the TypeScript compiler does not complain if you do so. With trivial type definitions for endorse and declassify, we can write statically- typed, tierless programs using TypeScript and Fission. Moreover, we can leverage IDEs like Visual Studio which have powerful support for TypeScript programming. Without Fission, TypeScript cannot reason about the client and server code in tandem, but Fission makes it trivial for TypeScript to do so. 7 Fission for Other Languages Although Fission is engineered to support JavaScript, it is hopefully clear to the reader that the approach is not JavaScript-specific and could be applied to other programming languages too. The most natural candidates are other dynamic languages. For example Ruby and Python are not dissimilar to JavaScript and have support programming idioms that have been challenging to statically-check [24, 4, 34]. Therefore, the Fission approach is likely to suit these languages too. The Fission approach is useful even with certain statically typed languages. Whereas languages like Links [18], Ur/Web [12], and Swift [13] have type systems that are explicitly designed to support tier-splitting, the Fission approach can be applied to statically languages that were not designed with tier-splitting and information flow control in mind. For example, Section 6 describes we applied Fission to (the JavaScript output of) programs written in TypeScript and Elm. 8 Related Work Fission builds on a long line of research on tierless web programming languages, some of which we’ve already mentioned. Fission is directly inspired by Swift [13] which uses static IFC and static analysis to partition JIF programs across the client and server. Fission’s emphasis on dynamic techniques and JavaScript makes it easy for us to support reams of existing JavaScript code and presents new challenges and opportunities. Hop.js [53] is a tierless language that is also ECMAScript-compatible and supports both NodeJS and browser APIs. Unlike Fission, Hop.js is a syntactic superset of JavaScript because it uses a special quoting syntax to explicitly demarcate the boundary between client and server code. In contrast, Fission does not change the syntax of JavaScript and thus can be used in several ways that Hop.js cannot. First, a Hop.js program cannot be consumed by ordinary JavaScript analyses and refactoring tools. Second, Hop.js cannot be used to add SNAPL 2017 5:10 Fission: Secure Dynamic Code-Splitting for JavaScript server-side features to Elm (without changing the Elm compiler to generate Hop.js). Finally, Hop.js does not implement information flow control. Fission does not syntactically distinguish client-side and server-side code, which is similar to the design of Swift and Links.4 In contrast, in languages like Ur/Web [12], Hop [52], and Hop.js [53] it is syntactically evident when control crosses tiers. It is not clear to the authors which language design is intrinsically superior. However, since Fission does not add any new syntax to JavaScript, we get to reuse existing libraries and JavaScript developer tools. Most web applications have three tiers: client, server, and database, and tierless languages like Links and Ur/Web unify all three tiers into a single language. Fission, with its emphasis on JavaScript, only unifies the client and the server. It is unclear if all three tiers can be unified satisfactorily for JavaScript without intentional language design (e.g., LINQ [41]). Fission’s tierless programming abstraction is built on top of an implementation of remote procedure calls [8] and distributed shared memory [3]. These abstractions require inter- machine communication, which can be optimized in several ways. For example, Remote Batch Invocation [31, 17] adds a language construct to batch several remote procedure calls together, which reduces the number of message round-trips incurred. These kinds of techniques are likely to improve Fission’s performance, which currently uses very simple implementation techniques. Fission’s dynamic information flow control mechanism is based on faceted execution, which dynamically tracks implicit and explicit information flows in a fine-grained manner. However, there are alternative language-based approaches, such as Laminar [48], which is designed to make it easy to retrofit information flow control. For performance, the Laminar system requires virtual machine and operating system changes. However, Laminar’s language abstractions could be adapted for JavaScript (with or without changing the VM). A possible future avenue for research may be to leverage Laminar-style “security regions” to make tier-splitting more efficient. Acknowledgments. We thank the SNAPL’17 reviewers and our shepherd, Ranjit Jhala, for their thoughtful feedback and suggestions. References 1 Amal Ahmed. Verified compilers for a multi-language world. In Summit oN Advances in Programming Languages (SNAPL), 2015. 2 Devdatta Akhawe, Adam Barth, Peifung E. Lam, John C. Mitchell, and Dawn Song. To- wards a formal foundation of Web security. In IEEE Computer Security Foundations Sym- posium (CSF), 2010. 3 Cristiana Amza, Alan L. Cox, Sandhya Dwarkadas, Pete Keleher, Honghui Lu, Ramakrish- nan Rajamony, Weimin Yu, and Willy Zwaenepoel. TreadMarks: Shared memory comput- ing on networks of workstations. Computer, 29(2):18–28, February 1996. 4 Jong-hoon David An, Avik Chaudhuri, and Jeffrey S. Foster. Static typing for Ruby on Rails. In IEEE International Symposium on Automated Software Engineering, 2009. 5 Christopher Anderson, Paola Giannini, and Sophia Drossopoulou. Towards type inference for JavaScript. In European Conference on Object-Oriented Programming (ECOOP), 2005. 6 Esben Andreasen and Anders Møller. Determinacy in static analysis for jQuery. In ACM SIGPLAN Conference on Object Oriented Programming, Systems, Languages and Applica- tions (OOPSLA), 2014. 4 Links supports optional placement annotations. A. Guha, J. B. Jeannin, R. Nigam, R. Shambaugh, and J. Tangen 5:11 7 Thomas H. Austin and Cormac Flanagan. Multiple facets for dynamic information flow control. In ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages (POPL), 2012. 8 Andrew D. Birrell and Bruce Jay Nelson. Implementing remote procedure calls. ACM Transactions on Computer Systems (TOCS), 2(1):39–59, February 1984. 9 Martin Bodin, Arthur Chargueraud, Daniele Filaretti, Philippa Gardner, Sergio Maffeis, Daiva Naudziuniene, Alan Schmitt, and Gareth Smith. A trusted mechanised JavaScript specification. In ACM SIGPLAN-SIGACT Symposium on Principles of Programming Lan- guages (POPL), 2014. 10 Bounty hunters: The honor roll. https://technet.microsoft.com/en-us/security/ dn469163.aspx. Accessed Mar 24 2017. 11 Satish Chandra, Colin S. Gordon, Jean-Baptiste Jeannin, Cole Schlesinger, Manu Sridha- ran, Frank Tip, and Young-Il Choi. Type inference for static compilation of JavaScript. In ACM SIGPLAN Conference on Object Oriented Programming, Systems, Languages and Applications (OOPSLA), 2016. 12 Adam Chlipala. Ur/Web: A simple model for programming the web. In ACM SIGPLAN- SIGACT Symposium on Principles of Programming Languages (POPL), 2015. 13 Stephen Chong, Jed Liu, Andrew C. Myers, Xin Qi, K. Vikram, Lantian Zheng, and Xin Zheng. Secure web applications via automatic partitioning. In ACM Symposium on Operating Systems Principles (SOSP), 2007. 14 Ravi Chugh, David Herman, and Ranjit Jhala. Dependent types for JavaScript. In ACM SIGPLAN Conference on Object Oriented Programming, Systems, Languages and Applica- tions (OOPSLA), 2012. 15 Ravi Chugh, Jeffrey A. Meister, Ranjit Jhala, and Sorin Lerner. Staged information flow for JavaScript. In ACM SIGPLAN Conference on Programming Language Design and Implementation (PLDI), 2009. 16 Ravi Chugh, Patrick M. Rondon, and Ranjit Jhala. Nested refinements for dynamic lan- guages. In ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages (POPL), 2012. 17 William R. Cook and Ben Wiedermann. Remote batch invocation for SQL databases. In International Symposium on Database Programming Languages (DBPL), 2011. 18 Ezra Cooper, Sam Lindley, Philip Wadler, and Jeremy Yallop. Links: Web programming without tiers. In Formal Methods of Components and Objects, 2006. 19 Brian J. Corcoran, Nikhil Swamy, and Michael Hicks. Cross-tier, label-based security enforcement for web applications. In ACM SIGMOD International Conference on Manage- ment of Data (SIGMOD), 2009. 20 CVE-2016-6316: XSS vulnerability in Action View in Ruby on Rails. https://cve.mitre. org/cgi-bin/cvename.cgi?name=CVE-2016-6316. Accessed Mar 24 2017. 21 Evan Czaplicki and Stephen Chong. Asynchronous functional reactive programming for GUIs. In ACM SIGPLAN Conference on Programming Language Design and Implementa- tion (PLDI), 2013. 22 Facebook bug bounty: $5 million paid in 5 years. https://www.facebook.com/ notes/facebook-bug-bounty/facebook-bug-bounty-5-million-paid-in-5-years/ 1419385021409053/. Accessed Mar 24 2017. 23 Cedric Fournet, Nikhil Swamy, Juan Chen, Pierre-Evariste Dagand, Pierre-Yves Strub, and Benjamin Livshits. Fully abstract compilation to JavaScript. In ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages (POPL), 2013. 24 Michael Furr, Jong-hoon David An, and Jeffrey S. Foster. Profile-guilding static typing for dynamic scripting languages. In ACM SIGPLAN Conference on Object Oriented Program- ming, Systems, Languages and Applications (OOPSLA), 2009. SNAPL 2017 5:12 Fission: Secure Dynamic Code-Splitting for JavaScript 25 Google security rewards–2015 year in review. https://security.googleblog.com/2016/ 01/google-security-rewards-2015-year-in.html. Accessed Mar 24 2017. 26 Salvatore Guarnieri and Benjamin Livshits. GateKeeper: Mostly static enforcement of security and reliability policies for JavaScript code. In USENIX Security Symposium, 2009. 27 Arjun Guha, Shriram Krishnamurthi, and Trevor Jim. Using static analysis for Ajax intrusion detection. In World Wide Web Conference (WWW), 2009. 28 Arjun Guha, Claudiu Saftoiu, and Shriram Krishnamurthi. The essence of JavaScript. In European Conference on Object-Oriented Programming (ECOOP), 2010. 29 Arjun Guha, Claudiu Saftoiu, and Shriram Krishnamurthi. Typing local control and state using flow analysis. In European Symposium on Programming (ESOP), 2011. 30 Phillip Heidegger and Peter Thiemann. Recency types for dynamically-typed, object-based languages: Strong updates for JavaScript. In Workshop on Foundations of Object-Oriented Languages (FOOL), 2009. 31 Ali Ibrahim, Yang Jiao an d Eli Tilevich, and William R. Cook. Remote batch invocation for compositional object services. In European Conference on Object-Oriented Programming (ECOOP), 2009. 32 JIF 3.5.0: Java information flow. https://www.cs.cornell.edu/jif. June 2016. 33 Vineeth Kashyap, Kyle Dewey, Ethan A. Kuefner, John Wagner, Kevin Gibbons, John Sarracino, Ben Wiedermann, and Ben Hardekopf. JSAI: A static analysis platform for JavaScript. In ACM SIGSOFT Symposium on the Foundations of Software Engineering (FSE), 2014. 34 Jukka Lehtosalo. mypy. http://mypy-lang.org. 35 Benjamin S. Lerner, Liam Elberty, Jincheng Li, and Shriram Krishnamurthi. Combining form and function: Static types for JQuery programs. In European Conference on Object- Oriented Programming (ECOOP), 2013. 36 Benjamin S. Lerner, Joe Gibbs Politz, Arjun Guha, and Shriram Krishnamurthi. TeJaS: Retrofitting type systems for JavaScript. In Dynamic Languages Symposium (DLS), 2013. 37 Magnus Madsen, Frank Tip, and Ondrej Lhoták. Static analysis of event-driven Node.js JavaScript applications. In ACM SIGPLAN Conference on Object Oriented Programming, Systems, Languages and Applications (OOPSLA), 2015. 38 Sergio Maffeis, John C. Mitchell, and Ankur Taly. An operational semantics for JavaScript. In Asian Symposium on Programming Languages and Systems, 2008. 39 Sergio Maffeis, John C. Mitchell, and Ankur Taly. Isolating JavaScript with filters, rewrit- ing, and wrappers. In European Symposium on Research in Computer Security, 2009. 40 Jacob Matthews and Robert Bruce Findler. Operational semantics for multi-language pro- grams. In ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages (POPL), 2007. 41 Erik Meijer, Brian Beckman, and Gavin Bierman. LINQ: Reconciling object, relations and XML in the .NET Framework. In ACM SIGMOD International Conference on Management of Data (SIGMOD), 2006. 42 Joseph Menn. U.S. election agency breached by hackers after November vote. http://www. reuters.com/article/us-election-hack-commission-idUSKBN1442VC. Accessed Jan 2 2017. 43 Peter-Michael Osera, Vilhelm Sjöberg, and Steve Zdancewic. Dependent interoperability. In Programming Languages meets Program Verification Workshop (PLPV), 2012. 44 Daejun Park, Andrei Stefănescu, and Grigore Roşu. KJS: A complete formal semantics of JavaScript. In ACM SIGPLAN Conference on Programming Language Design and Imple- mentation (PLDI), 2015. A. Guha, J. B. Jeannin, R. Nigam, R. Shambaugh, and J. Tangen 5:13 45 Joe Gibbs Politz, Matthew J. Carroll, Benjamin S. Lerner, and Shriram Krishnamurthi. A tested semantics for getters, setters, and eval in JavaScript. In Dynamic Languages Symposium (DLS), 2012. 46 Joe Gibbs Politz, Spiridon Aristides Eliopoulos, Arjun Guha, and Shriram Krishnamurthi. Adsafety: Type-based verification of javascript sandboxing. In USENIX Security Sympo- sium, 2011. 47 Joe Gibbs Politz, Arjun Guha, and Shriram Krishnamurthi. Semantics and types for objects with first-class member names. In Workshop on Foundations of Object-Oriented Languages (FOOL), 2012. 48 Donald E. Porter, Michael D. Bond, Indrajit Roy, Kathryn S. McKinley, and Emmett Witchel. Practical fine-grained information flow control using Laminar. ACM Transactions on Programming Languages and Systems (TOPLAS), 37(1):4:1–4:51, 2014. 49 Gregor Richards, Sylvain Lebresne, Brian Burg, and Jan Vitek. An analysis of the dy- namic behavior of JavaScript programs. In ACM SIGPLAN Conference on Programming Language Design and Implementation (PLDI), 2010. 50 Gregor Richards, Francesco Zappa Nardelli, and Jan Vitek. Concrete types for TypeScript. In European Conference on Object-Oriented Programming (ECOOP), 2015. 51 Daniel Schoepe, Musard Balliu, Frank Piessens, and Andrei Sabelfeld. Let’s face it: Faceted values for taint tracking. In European Symposium on Research in Computer Security, 2016. 52 Manuel Serrano, Erick Gallesio, and Florian Loitsch. Hop, a language for programming the Web 2.0. In Dynamic Languages Symposium (DLS), 2006. 53 Manuel Serrano and Vincent Prunet. A glimpse of Hopjs. In ACM International Conference on Functional Programming (ICFP), 2016. 54 Ankur Taly, Úlfar Erlingsson, Mark S. Miller, John C. Mitchell, and Jasvir Nagra. Auto- mated analysis of security-critical JavaScript APIs. In IEEE Security and Privacy (Oak- land), 2011. 55 Peter Thiemann. Towards a type system for analyzing JavaScript programs. In European Symposium on Programming (ESOP), 2005. 56 Peter Thiemann. A type safe DOM API. In International Workshop on Database Program- ming Languages, 2005. 57 Panagiotis Vekris, Benjamin Cosman, and Ranjit Jhala. Trust, but verify: Two-phase typing for dynamic languages. In European Conference on Object-Oriented Programming (ECOOP), 2015. 58 WordPress 4.6.1 security and maintenance release. https://wordpress.org/news/2016/ 09/wordpress-4-6-1-security-and-maintenance-release/. Accessed Mar 24 2017. SNAPL 2017