190 likes | 281 Views
Type-directed coercion insertion for security enforcement . Michael Hicks , University of Maryland Nik Swamy, MSR Redmond Gavin Bierman, MSR Cambridge. Secure programming with proxies Fable: Type-correctness = Security. Flexible : Can enforce of a wide range of policies
E N D
Type-directed coercion insertion for security enforcement Michael Hicks, University of Maryland Nik Swamy, MSR Redmond Gavin Bierman, MSR Cambridge
Secure programming with proxiesFable: Type-correctness = Security • Flexible: Can enforce of a wide range of policies • Information flow controls: MLS, provenance tracking, tainting • Various styles of access controls • Policies specified as automata • Verifiable: Can prove type-correct programs secure • Programs using MLS proxies enjoy a noninterference property • Access control proxies give a related correctness condition • BUT: Not always easy to use • Number of extra API calls can be very large (for some policies) • Breaks old code Fable: A language for enforcing user-defined security policies Swamy, Corcoran, Hicks; IEEE S&P (Oakland) 2008 (Caveat: Using somewhat fancier dependent types etc.)
A theory of typed coercionsAutomatically rewrite programs with calls to security API • The type Secure String is a proxy for a normal String • x = (TOP_SECRET, “Bob’s a spy”): Secure String • Treat Secure String values as Stringvalues • y = “Bob works for the US Govt.” : String • z = strcat(x,y) : ?? • But this program is not type-correct (or secure) • Experts define type coercions to secure the API • sec: String -> Secure String • lift: (a*b -> c) -> (Secure a*Secure b -> Secure c) • Our theory shows how to insert coercions so as to unambiguously “correct” a type-incorrect program • z = (lift(strcat)) (x,sec(y))
Coercion insertion is broadly applicable • Lazy evaluation in strict languages • Operator overloading • E.g., overloaded addition • Equality-witnessing coercions • E.g., for witnesses in type-preserving compiler IRs • Gradual typing • For converting between static and dynamically-typed values • Information flow controls • Tainting and sanitization for web applications • For tracking the provenance of computed values derived from their original sources
Operator overloadingA simple example of coercion insertion • Environment Γ = +:PlusOp • Coercion set Σ = • plus_for_int:PlusOp -> int -> int -> int • plus_for_float:PlusOp -> float -> float -> float • Rewrite programs: • Σ; Γ |-- + 1 2 ~>(plus_for_int +) 1 2 :int • Σ; Γ |-- + 1.0 2.0~>(plus_for_float +) 1.0 2.0 :float • But not all programs can be corrected • Σ; Γ |-- + 1.0 2~>??? • Should we just add more coercions? • Σ’ = Σ,int2float:int -> float
Environment Γ: +:PlusOp Coercion set Σ’: plus_for_int:PlusOp -> int -> int -> int plus_for_float:PlusOp -> float -> float -> float int2float:int -> float Key Problem:Ambiguous rewritings • More coercions means more programs can be rewritten: • Σ’; Γ |-- + 1.0 2 ~>(plus_for_float +) 1.0 (int2float 2) :float • But, there may be several rewritings of some programs: • Σ’; Γ |-- + 1 2 ~>(plus_for_int +) 1 2 :int • Σ’; Γ |-- + 1 2 ~>(plus_for_float +) (int2float 1) (int2float 2) :float • Programmers can resolve ambiguity with annotations • Σ’; Γ |-- (+ 1 2):int ~>(plus_for_int +) 1 2 :int • But maybe rewriting can produce syntactically distinct terms that really have the same semantics?
Handling ambiguity syntactically • Syntactic distinction does not always imply different semantics: • Σ; Γ |-- let y = (λx:int.F) 0 in (e; 1+y) ~> • let y = (λx:int.(float2int F)) 0 in (e; 1+y) : int OR let y = (λx:int.F) 0 in (e; 1+(float2int y)) : int • But what if float2intcan fail when F = NaN? Effects in e would be observable in the first case, but not the second • Reasoning about such cases semantically is difficult, and specific to the choice of coercions • We give a precise yet purely syntactic treatment of ambiguity
A theory of typed coercionsCore judgments • Coercion generation Coercion insertion • The index d denotes a particular coercion generation def. • M is a setof rewritten target terms {m1:t1, …,mn:tn} • When |M| = 1, rewriting is unambiguous • Define constraints on Σ to ensure rewriting is unambiguous • Every element of M is both syntactically and semantically distinct
Claim: Coercion insertion provides a general framework for retrofitting programs with security enforcement
ExampleSanitizing strings in a web app • Application must assemble a dynamic HTML page from user input, database queries, … • Sanitizing strings of script content depends on the context in which that string appears • Escape < with < for HTML • Escape ‘ with ‘’ for SQL strings • Sanitize using safe URL encodings • Filter out blacklisted property values in CSS
A typed DOM interfaceIn GWT, Links, Volta, … • Types reflect sanitization requirements • String,UserString, HTMLString, etc. • API • strcat: String -> String -> String • getReq: HTTPRequest -> String -> UserString • setInnerHTML: DOMElement -> HTMLString -> Unit • getInnerHTML: DOMElement -> HTMLString • Coercion set • sanitizeHTML: UserString-> HTMLString • lift2HTML: (String -> String -> String) -> (HTMLString -> HTMLString -> HTMLString)
Programming with the API leteditPage(page:DOMElement, req:HTTPRequest) = lettext:UserString= getParamreq "textbox" in letnode:DOMElement = getNodeById page "id" in letnewtext:HTMLString= strcat (getInnerHTML node) text in setInnerHTML node newtext
Programming with the API leteditPage(page:DOMElement, req:HTTPRequest) = lettext:UserString= getParamreq "textbox" in letnode:DOMElement = getNodeById page "id" in letnewtext:HTMLString= (lift2HTML strcat) (getInnerHTML node) (sanitizeHTMLtext) in setInnerHTML node newtext
ExampleProvenance tracking in DB queries Each row tagged with a label indicating the data’s origin Each cell of query result tagged with provenance of rows that contributed to the result
A minimal model of database tables • Model a table as a list of records • xrefsTab: List (rid:int * pid:int) • Records tagged with labels are given a proxy type • (rid:1, name:”G(1)”, prov:Lab1) : Prov (rid:int * name:string) • reactionsTab: List (Prov (rid:int * name:string)) • enzymesTab: List (Prov (pid:int * name:string * mwgt:float)) • Queries are just functions from lists of records (tables) to lists of records (tables)
Type environment: +: float -> float -> float xrefsTab:List (Prov (rid:Int * pid:int)) reactionsTab:List (Prov (rid:Int * name:string)) enzymesTab:List (Prov enzyme) lookup:int -> List (Prov enzyme) -> enzyme A source query(oblivious to provenance tracking) functionaggrWgts(rid:int, sum:Prov float, xref: (rid:int * pid:int)){ if rid != xref.ridthen return sum else var enzyme = lookup xref.pidenzymesTab; return sum + enzyme.mwgt } Sub-query aggregates the weights of all enzymes in the reaction rid. Written as a function of records in the xrefsTab functionquery(reac: (rid:int * name:string)){ return (reac.name, aggrWgtsreac.rid 0 xrefsTab) } query reactionsTab A query is just a function on each record in a table That is then applied to the entire table
Coercions for provenance tracking asprod: All a,b. Prov (a * b) -> Prov a * Prov b asfun: All a,b. Prov (a -> b) -> Prov a -> Prov b lift: All a. a -> Prov a Propagates the provenance label on a record to each field of the record reaction: Prov(rid:int * name:string) (asprod reaction):Prov(rid:int) * Prov(name:string) map: All a,b. (a -> b) -> List a -> List b fold: All a,b. (a -> b -> a) -> a -> List b -> a Can prove that these functions are sufficient to correctly enforce a security property for provenance called dependency correctness Applies a function to each element of a list lookup_wgt: enzyme -> float (map lookup_wgt):List enzyme -> List float
Query retro-fitted with provenance tracking functionaggrWgts(rid:int, sum:Prov float, xref: (rid:int * pid:int)){ if rid != xref.ridthen return sum else varenzyme = lookup xref.pidenzymesTab; return (asfun(asfun◦lift+) sum) ((asprodenzyme).mwgt) } :int -> Prov float -> (rid:int * pid:int) -> Prov float functionquery(reac: (rid:int * name:string)){ return (liftreac.name, fold (aggrWgtsreac.rid) (lift 0) xrefsTab) } : (rid:int * name:string) -> Prov string * Prov float (map ◦ asfun ◦ lift query) reactionsTab : List Prov(Prov String * Prov Float)
Claim: Coercion insertion provides a general framework for retrofitting programs with security enforcement Lots left to do: Handling richer types Bettercharacterization of ambiguity Integrationwith type inference Efficient rewriting algorithms