Wyvern:Designing a Language for Security
Jonathan [email protected]
http://www.cs.cmu.edu/~aldrich/
17-396: Language Design and Prototyping
Spring 2020
School of Computer Science
contributions from:Aaron CraigJustin LubinDarya MelicherCyrus OmarAlex PotaninAnlun XuValerie Zhao
Software security is a big problem!
2
lodash node module before 4.17.5 suffers from a Modification of Assumed-Immutable Data (MAID) vulnerability via defaultsDeep, …
Prototype pollution attack (lodash)
The 10 Worst Security Vulnerabilities of 2018#3: The pdfinfojs NPM module for versions <= 0.3.6 allows for command injection, allowing an attacker to execute arbitrary commands to the machine.
October 17, 2018Security flaw in libssh leaves thousands of servers at risk of hijacking
Why Systems are Vulnerable?
• We “know” how to code securely• Follow the rules: CERT, Oracle, …• Technical advances: type, memory safety
• But we still fail too often!
• Root causes• Coding instead of engineering• Human limitations• Unusable tools
3
Our Approach: Usable Architecture-Based Security
4
Secure systemsdevelopment
Outline – 3 issues• Tampering w/mutable data
Immutability• Command injection
Type-specific languages• Resource use
Capabilities and effects
Bridge icon credit: iconsmind.comLock icon credit: Appzgear at flaticon.comWyvern credit: Zigeuner
Engineering:An architecture/design
perspective
Settings• Java (some studies)• Wyvern, a programming
language designed following these principles
Formal modeling:A mathematical perspective
Usability:A human
perspective
Immutability: An Architectural Perspective
• Architecture: “the set of principal design decisions about the system” [Garlan and Shaw 1996; Taylor et al. 2009]
• Typically large in scope
• Non-architectural• final in Java: one field only, non-transitive• const in C++: protects through one reference only• Both weak reasoning: partial protection of data structure
• Architectural• Transitive immutability: entire data structure protected• Strong reasoning – for security, concurrency, etc.• Interview studies: programmers want guarantees that only
transitive immutability can provide [Coblenz et al. ICSE 2017]
5
Formal modeling: enforcing immutability
• How to enforce transitive immutability, technically?• Design decisions based on type systems / soundness proofs
6
Formal grammar Static semantics
Dynamic semantics
Usability Experiments
• 20 experienced Java programmers, 10 each in Java and Glacier
• Compared errors/vulnerabilities and completion rates (Java Glacier)
• Unsuprising: no errors in Glacier condition
• Surprising (perhaps): Glacier didn’t slow people down much
• Usability results still uncommon for type systems• We should do more!
7
errors completion
Enforcing immutability 10 0 10 7
FileRequest.execute() security task 4 0 8 8
HashBucket.put() task 7 0 10 7
Wyvern
• Design goals• Sound, modern language design• Type- and memory-safe, mostly functional, advanced module system
• Incorporate usability principles [Coblenz et al. Onward! 2018]• Security mechanisms built in• E.g. cleaner than Glacier retrofit to Java
• Immutability support• Default: transitive immutability• resource indicates types abstracting OS resources or mutable state
8
http://wyvernlang.github.io/
Demo: Immutability in Wyvern (examples/types/person.wyv)
Discuss: how is immutability cleaner in Wyvern than in Glacier?
Our Approach: Usable Architecture-Based Security
9
Immutability inWyvern
Engineering:Transitive immutability
has architectural benefits
Formal modeling:Proof of transitive immutability
Outline – 3 issues• Tampering w/mutable data
Immutability• Command injection
Type-specific languages• Resource use
Capabilities and effects
Settings• Java (some studies)• Wyvern, a programming
language designed following these principles
Usability:Simple design,experimentally
proven effective
SQL Command Injection
10
ExampleString s = "SELECT * FROM Students WHERE name ='" + studentName + "';"
"SELECT * FROM Students WHERE name ='Robert'; DROP TABLE Students; --';"
credit XKCD: HTTP://XKCD.COM/327/
Now plug in the name:Robert'; DROP TABLE Students; --
The data now includes an injected SQL command
Many similar issues• HTML (cross-site scripting)• Shell scripts (command
injection)• …
SQL Injection: a Solved Problem?
PreparedStatement s = connection.prepareStatement(
"SELECT * FROM Students WHERE name = ?;");
s.setString(1, userName);
s.executeQuery();
• Evaluation• Usability: unnatural, verbose• Design: string manipulation captures domain poorly• Language semantics: largely lost – just strings• No typechecking, IDE services, …
11
XXX
Prepare a statement with a hole
Fill the holesecurely
Discuss: why might this solution be less than satisfactory?
Wyvern: Usable Secure Programming
• A SQL query in Wyvernconnection.executeQuery(~)
SELECT * FROM Students WHERE name = {studentName}
• Hypothesis: Wyvern version more natural and more usable• No empirical evaluation, yet• But Omar et al. [ICSE 2012] shows benefits of similar DSL IDE
plugins
12
~ introduces a domain-specific language (DSL) on the next indented lines
Semantically rich DSL. Can provide typchecking, syntax highlighting,…autocomplete, …
Safely incorporates dynamic data—as data, not a command
Technical Challenge: Syntax Conflicts
• Language extensions as libraries has been tried before• Example: SugarJ/Sugar* [Erdweg et al, 2010; 2013]
import XML, HTML
val snippet = ~
How do I <b>parse</b> this example?
13
Is it XML or HTML?
Syntax Conflicts: Wyvern’s Solution
import metadata XML, HTML
val snippet : XML = ~
How do I <b>parse</b> this example?
14
metadata keyword indicates we are importing syntax, not just a library
No ambiguity: the compiler loads the unique parser associated with the expected type XML
Syntax of language completely unrestricted – indentation separates from host language
Thinking About Wyvern’s Solution
import metadata XML, HTML, SQL
val snippet : XML = ~
How do I <b>parse</b> this example?
connection.executeQuery(~)
SELECT * FROM Students WHERE name = {studentName}
15
Discuss: what might be possible downsides of this design?
Technical Challenge: Semantics
import metadata SQL
val connection = SQL.connect(…)
val studentName = input(…)
connection.executeQuery(~)
SELECT * FROM Students WHERE name = {studentName}
16
Language definition includes custom typechecker – can verify query against database schema
SQL extension has access to variables and their types in Wyvern host language
Splicing theory ensures capture-avoiding substitution in code generated by SQL extension – safe to use host language variables
Q: Is it safe to run custom parser at compile time?A: Yes – immutability types used to ensure imported metadata is purely functional, has no network access, etc.
Wyvern demo
• wyvern/examples/tsls• formatstringClient.wyv (format strings)• postfixClient.wyv (list and postfix arithmetic)
17
Our Approach: Usable Architecture-Based Security
18
DSL support inWyvern
Engineering:Express design in
domain-specific way
Formal modeling:Type safety, variable hygiene,
conflict-free extensions
Outline – 3 issues• Tampering w/mutable data
Immutability• Command injection
Domain-specific languages• Resource use
Capabilities and effects
Settings• Java (some studies)• Wyvern, a programming
language designed following these principles
Usability:Natural syntax,enabling IDE
suppoert
Resource Use
• SQL extensions are nice!• But what if people use a low-level, string-based library anyway?• More broadly, what if people misuse resource-access libraries?
19
What might code do to system resources?
• Example scenario: constraining plugins
20
Are these plugins safe? Could a malicious plugin delete my files?
What might code do to system resources?
• What can a plugin do?• File reads, writes?• Log an error message?• Like a file write, but more abstract
21
My app Plugin
What might code do to system resources?
• Goal: enforce architectural layering• Application code gets data using a• Query ADT, which is implemented via a• SQL library, which sends commands via a• Network driver, which talks to database
• Security constraints• Network used only for database queries• No direct use of string-based SQL library• Possible command injection
• Abstraction of system resources• Application does safe queries• Query ADT does unsafe queries• Network driver does network access
22
String-basedSQL library
Query ADT
Application code
Networkdriver
[Dijkstra 1968]
Two views of the resource use problem
23
How to reason formally about resource use?
How to practically enforce resource use?
Can we be just as lightweight as the practical approach, but retain formal reasoning?
Formalist: Let’s check this statically!
24
An effect system sounds like a good idea!
Checking Resource Use with Effects
• Effect systems [Lucassen & Gifford 88]
• Annotate each function with its effects• Our setting: effects are actions on resources• {passwordFile.read, wikipediaURL.request, …}
type File
effect read
def readContents(): {this.read} String
module def myPlugin(f:File)
def countWords() : { } Int
val contents = f.readContents()
contents.split(’ ’).size()
25
File resources define a read effect(cf. type members in Scala)
readContents has a read effect on this file
myPlugin is a functor that is instantiated with a File
What are the effects of countWords()?
?
Checking Resource Use with Effects
• Effect systems [Lucassen & Gifford 88]
• Annotate each function with its effects• Our setting: effects are actions on resources• {passwordFile.read, wikipediaURL.request, …}
type File
effect read
def readContents(): {this.read} String
module def myPlugin(f:File)
def countWords() : {f.read} Int
val contents = f.readContents()
contents.split(’ ’).size()
26
File resources define a read effect(cf. type members in Scala)
readContents has a read effect on this file
myPlugin is a functor that is instantiated with a File
readContents has effect f.read, so countWords does too
Checking Architectural Layering
// in signature of the rawSQL module
effect UnsafeQuery
type Connection
def connect(…) : Connection
def query(q:String) : {UnsafeQuery} SQLResult
// client code
def getData(input : String) : Data
rawSQL.query("SELECT * FROM Students WHERE name ='“
+ input + "';“)
27
Query operations have an UnsafeQuery effect
The unsafe SQL library defines an UnsafeSQL effect
Has effect rawSQL.UnsafeQuery
Error: getData() must declare effect rawSQL.UnsafeQuery
Checking Architectural Layering
// in signature of the rawSQL module
effect UnsafeQuery
type Connection
def connect(…) : Connection
def query(q:String) : {UnsafeQuery} SQLResult
// client code
def getData(input : String) : {rawSQL.UnsafeQuery} Data
rawSQL.query("SELECT * FROM Students WHERE name ='“
+ input + "';“)
28
Query operations have an UnsafeQuery effect
The unsafe SQL library defines an UnsafeSQL effect
Has effect rawSQL.UnsafeQuery
All dangerous code marked with effect
Effect Abstraction
• Issue: won’t users of the safeSQL library have an UnsafeQuery effect, if safeSQL is built on rawSQL?
module def safeSQL(rawSQL:RawSQL) : SafeSQL
type SQL
val command : String
…
effect SafeQuery = rawSQL.UnsafeQuery
def query(SQL) : {SafeQuery} SQLResult
…
29
Defines a SQL ADT
The safeSQL functor uses a rawSQL module
The SafeQuery effect is defined in terms of UnsafeQuery.
Now clients have effect safeSQL.SafeQuery
Opaque Signature Ascription
• We can hide the definition of an effect• Abstract effects – analogous to abstract types in ML modules
[MacQueen, 1986]
30
module def safeSQL(rawSQL:RawSQL) : SafeSQL
type SQL
val command : String
…
effect SafeQuery = rawSQL.UnsafeQuery
def query(SQL) : {SafeQuery} SQLResult
…
type SafeSQL
type SQL // abstract
effect SafeQuery // abstract
def query(SQL)
: {SafeQuery} SQLResult
Effect abstraction Effect polymorphism
• We can now encode effect polymorphism• Cf. type members type polymorphism in Scala (and Wyvern)
// with polymorphism sugar
def twice[effect E](f : Int -> {E} Int, x:Int) : {E} Int
f(f(x))
twice[file.write](…)
// the desugared version, using only effect members
type EffectHolder
effect E
def twice(e:EffectHolder, f : Int -> {e.E} Int, x:Int) : {e.E} Int
f(f(x))
twice(new EffectHolder{effect e=file.write}, …)31
Abstraction all the way down
• Primordial effect: the foreign function interface• All other I/O effects defined in terms of this• Can also “fake” an effect (no underlying I/O)
module net(java:Java)
import java:wyvern.utils.net.javaPacketUtils
effect Network = system.FFI
type Packet
…
def send(p:Packet) : {Network} Unit
javaPacketUtils.send(p)
32
The net functor takes the Java FFI object as an argument
Methods imported from Java automatically have the system.FFI effect
Network is an abstract effect defined in terms of system.FFI
Calls a Java function, therefore has system.FFI effect; abstracted to clients as a Network effect
Demo – Effects in Wyvern
33
rawSQL
safeSQL
Application code
JDBCdriver
Discuss this effect system design. Compare to:• Java’s exception system• A system with only one built-in “I/O effect”• No effects at all• Other points of comparison?
Is Abstraction Safe?
• The safeSQL abstracts the UnsafeQuery effect as a SafeQuery effect• OK; safeSQL protects from command injection• But couldn’t a malicious library also do this?
• Idea: analyze code for abstraction• UnsafeQuery is abstracted only by safeSQL, and only
as a SafeQuery• Currently formalizing and implementing this
34
rawSQL
safeSQL
Application code
JDBCdriver
Two much annotation?
• Effect system overhead causes problems• E.g. Java’s checked exceptions• Routinely bypassed using unchecked exceptions
• Inference [Talpin&Jouvelot 1994] is a solution, but has tradeoffs• Avoids need to annotate in many places• Only applies if you have the code• Usability issues• can fail because of something deep in the code• can succeed, then fail if the code changes
35
Not sure I want to write effects everywhere!
Object capabilities
• Capability: an unforgeable token controlling access to a resource [Dennis & Van Horn 1966]
• Benefits• Simple approach to security• Principle of least privilege [Saltzer 1974]
• Object capability: object reference grants access to resource• Recent research: E [Miller 2006], Joe-E [Mettler et al. 2010]
• Frozen Realms proposal for JavaScript
• Note: our capabilities are object references (dynamic)• Capability has also been used for permissions in a type system
(static)
36
Capability Safety
• No ambient authority• Code cannot use system resources by default• main gets a capability to system resources from OS• Other modules can use resources only if main passes it to them• Pass only the capabilities each module needs• Often at functor instantiation time
• Formalized as capability safety [Maffeis et al. 2010]
• Adapted for Wyvern [Melicher et al. 2017]
37
mainmodule
Anothermodule
Anothermodule
Anothermodule
OperatingSystem
Passescapabilities
to
Passescapabilities
to
Capability Safety
// the safeSQL module
module def safeSQL(stringSQL : db.StringSQL)
type SSQL = …
type Sselect = …
def select(row:String):SQLSelect =
…
// the main program
require db.stringSQL
import db.safeSQL
import modules.sqlApplication
val sql = safeSQL(stringSQL)
val app = sqlApplication(sql)
app.run()
38
stringSQL
safeSQL
sqlApplication
safeSQL can’t just import StringSQL; it must be passed a capability
main requires a stringSQL capability from the OS
These modules are pure (stateless) functors and can be imported
We instantiate the modules, passing capabilities
Capabilities all the way down
• The primordial capability is the FFI• “require db.stringSQL” instantiates
stringSQL with a java FFI capability:// the stringSQL module
module def stringSQL(java : Java)
import java:wyvern.JDBC.utils
type SQL
def query():String
…
// the main program, now desugared
require java
import db.stringSQL
val ssql = stringSQL(java)
…39
stringSQL
safeSQL
sqlApplication
java(JDBC driver)
main requires a java FFI capability
stringSQL is a functorthat needs a java FFI capability to use JDBC
Import and instantiate stringSQL, then the other modules
Authority attenuation
• Capabilities give programs authority to access resources
• A capability can attenuate another by wrapping it in a restricted interface• Example: safeSQL wraps stringSQL, SQL-
encoding pasted strings to avoid command injection
40
stringSQL
safeSQL
sqlApplication
javaThe java FFI capability can access any system resource
stringSQL attenuates that to only accessing SQL databases
safeSQL attenuates that to only permit safe query composition
Provided the wrappers are correct:* sqlApplication can only access a database* SQL injection vulnerabilities impossible
Demo – Capabilities in Wyvern
41
stringSQL
safeSQL
sqlApplication
java
Discussion• Is the capability model intuitive?• How does it compare to other security
models you may be aware of?• Would you rather use effects or capabilities?
Comparing these mechanisms
Effects
• Static, mechanical reasoning• Effect annotation on a function
• Requires annotations• Can be burdensome
• Support abstraction• SafeQuery abstracts UnsafeQuery
• Build up from FFI effect
Capabilities
• Reason using dynamic semantics• Who has which capability?
• No annotations required• But must pass capabilities explicitly
• Support attenuation• safeSQL attenuates stringSQL
• Build up from java capability
42
Idea: can we combine these mechanisms?• Nearly as lightweight as capabilities• Retain formal reasoning of effects• Explain, formally, why capabilities are useful!
Capabilities are neat…but what do they really buy us?Formally, no one really knows.
Bounding effects with capabilities
• We can bound a module’s effects by its capabilities• No need to effect-annotate the module• Note: requires capability safety!
module def client(safeSQL : SafeSQL) : Client
import …
// other code
43
Client can have effect safeSQL.SafeQuery (and nothing else)
Imports must be pure - no effects
Safe SQLDSL library
Client code
Scales up – most application code may be unannotated
Effect bounding demo
44
Logger
Editor Plugin
uses
Annotated
Not AnnotatedConfigured to log to a file or the network
Legend
Capability effect computation: examples
What are the effects enabled by a capability of a given type?
1. effcap(Unit A Unit) = {A}
2. effcap(Unit A Unit B Unit) = {A,B}• Client can have effect A and then effect B
3. effcap((Unit A Unit) B Unit) = {B}• Client can have effect B, but does not gain the ability to have
effect A because the client produces the argument
4. effcap(((Unit A Unit) B Unit) C Unit) = {A,C}• Client can have effect C by calling the function, and effect A by
providing a function that gets a (Unit A Unit) and invokes it
45
Lifting effect polymorphism
module def repeaterPlugin(defaultLogger : Logger)
var logger : Logger = defaultLogger
def log(msg:String) : Unit = …
def setLogger(aLogger : Logger) : Unit
logger = aLogger
46
We would like to assign this function an effect-polymorphic type
But some functions might assign to local state, so the effect of log and setLoggermust be bounded by the overall effect of the module (cf. polymorphism and state, more generally)
Our solution is lifts poly-morphism to the module level, where the state is created
Comparison and tradeoffs vs. inference
Effect Inference
• Only requires effects
• Requires code
• Failure may depend on code• E.g. large components, evolution
Effect Bounds
• Requires capabilities & effects
• Requires only type
• Failure depends only on type• E.g. large components, evolution
• Explains value of capabilities for formal reasoning
47
Capabilities and Effects: So Happy Together
• Goal: controlling system resources
• Two approaches• Effect system, supporting abstraction• Capability safety, supporting attenuation
• A link between them: bounding effects with capabilities• Use lightweight approach for many components• Formally reason about the effect of all components• Bonus: formal explanation of the reasoning power of capabilities
48
Our Approach: Usable Architecture-Based Security
49
Effects and capabilitiesin Wyvern
Engineering:Architectural restrictions
on resource use
Formal modeling:Effect- and capability-safety,
effect bounds
Outline – 3 issues• Tampering w/mutable data
Immutability• Command injection
Domain-specific languages• Resource use
Capabilities and effects
Settings• Java (some studies)• Wyvern, a programming
language designed following these principles
Usability:Bound effects
based onarchitecture
Our Approach: Usable Architecture-Based Security
50
Secure systemsdevelopment
Engineering:An architecture/design
perspective
Formal modeling:A mathematical perspective
Outline – 3 issues• Tampering w/mutable data
Immutability• Command injection
Domain-specific languages• Resource use
Capabilities and effects
Settings• Java (some studies)• Wyvern, a programming
language designed following these principles
Usability:A human
perspective