490 likes | 499 Views
This paper discusses the use of types for static enforcement of security in programming languages, with a focus on Java security and stack inspection. It explores the benefits, limitations, and possible improvements of this approach, and provides examples and code snippets to illustrate the concepts.
E N D
Static Enforcement of Security with Types Christian Skalka and Scott Smith Johns Hopkins University
Background: PL Security • Non-local execution of code (e.g. Applets) presents new security problems • Some PLs provide user-level abstractions for security (Ambit, Spi-calculus, Java) • Built-in mechanisms allow expression and enforcement of various models/policies
Dataflow ensures security of data Certified Code (PCC) is an extremely general framework for extensible code security Access Controlis a flexible system of code ownership and resource authorization Varieties of Security
Dataflow ensures security of data Certified Code (PCC) is an extremely general framework for extensible code security Access Controlis a flexible system of code ownership and resource authorization Varieties of Security
Overview • Background: PL Security • Java JDK 1.2 and stack inspection • Using types instead of stack inspection • Security Types: formal properties • Possible improvements • Work in Progress • Conclusion
Java Security • Java JDK 1.2 provides a system for access control and code security • possibly non-local program execution requires protection of resources • All code has a specified owner, granted certain privileges locally • Resources are protected by a dynamic check (stack inspection)
Stack Inspection • Stack frames are annotated with names of owners and any enabled privileges • During inspection, stack frames are searched from most to least recent: • fail if a frame belonging to someone not authorized for privilege is encountered • succeed if activated privilege is found in frame
Example: privileged printing privPrint(f) = (* owned by system *) { checkPrivilege(PrintPriv); print(f); } foreignProg() = (* owned by Joe *) { …; privPrint(file); …; }
Stack Inspection (* local policy *) AccessCreds = { Joe ={???},… } (* owned by system *) enablePriv(PrintPriv); foreignProg();
Stack Inspection (* local policy *) AccessCreds = { Joe ={PrintPriv},… } (* owned by system *) enablePriv(PrintPriv); foreignProg();
Stack Inspection Main system (* local policy *) AccessCreds = { Joe = {PrintPriv},… } (* owned by system *) enablePriv(PrintPriv); foreignProg();
Stack Inspection Main system PrintPriv (* local policy *) AccessCreds = { Joe = {PrintPriv},… } (* owned by system *) enablePriv(PrintPriv); foreignProg();
Stack Inspection Main system PrintPriv (* local policy *) AccessCreds = { Joe = {PrintPriv},… } (* owned by system *) enablePriv(PrintPriv); foreignProg(); foreignProg joe
Stack Inspection Main system PrintPriv (* local policy *) AccessCreds = { Joe = {PrintPriv},… } (* owned by system *) enablePriv(PrintPriv); foreignProg(); foreignProg joe privPrint system
Stack Inspection Main system PrintPriv (* local policy *) AccessCreds = { Joe = {PrintPriv},… } (* owned by system *) enablePriv(PrintPriv); foreignProg(); foreignProg joe privPrint system
Stack Inspection Main system PrintPriv (* local policy *) AccessCreds = { Joe = {PrintPriv},… } (* owned by system *) enablePriv(PrintPriv); foreignProg(); success foreignProg joe privPrint system
Stack Inspection (* local policy *) AccessCreds = { Joe ={},… } (* owned by system *) enablePriv(PrintPriv); foreignProg();
Stack Inspection Main system PrintPriv (* local policy *) AccessCreds = { Joe ={},… } (* owned by system *) enablePriv(PrintPriv); foreignProg(); foreignProg joe privPrint system
Stack Inspection Main system PrintPriv (* local policy *) AccessCreds = { Joe ={},… } (* owned by system *) enablePriv(PrintPriv); foreignProg(); foreignProg joe failure privPrint system
Why Stack Inspection? • How is it different from a capability system? • Why not just use an access control matrix and a global set of allowable privileges? • Privileges not held by current code owner are removed from allowable set
Stack Inspection: Callbacks • Stack inspection allows security contexts to be temporarilyraised.
Stack Inspection: Callbacks • Stack inspection allows security contexts to be temporarilyraised: (* owned by system *) getIPaddr(url) = { checkPriv(IPPriv); addr = IPlookup(url); return addr; }
Callbacks (* owned by system *) appletIP(applet) = { enablePriv(IPPriv); url =applet.source(); return getIPaddr(url); } (* owned by Joe, not authorized for IPPriv *) getMyIP() = appletIP(this);
Callbacks getMyIP (* owned by system *) appletIP(applet) = { enablePriv(IPPriv); url =applet.source(); return getIPaddr(url); } (* owned by Joe, not authorized for IPPriv *) getMyIP() = appletIP(this); joe
Callbacks getMyIP (* owned by system *) appletIP(applet) = { enablePriv(IPPriv); url =applet.source(); return getIPaddr(url); } (* owned by Joe, not authorized for IPPriv *) getMyIP() = appletIP(this); joe appletIP system
Callbacks getMyIP (* owned by system *) appletIP(applet) = { enablePriv(IPPriv); url =applet.source(); return getIPaddr(url); } (* owned by Joe, not authorized for IPPriv *) getMyIP() = appletIP(this); joe appletIP system IPPriv
Callbacks getMyIP (* owned by system *) appletIP(applet) = { enablePriv(IPPriv); url =applet.source(); return getIPaddr(url); } (* owned by Joe, not authorized for IPPriv *) getMyIP() = appletIP(this); joe appletIP system IPPriv this.source joe
Callbacks getMyIP (* owned by system *) appletIP(applet) = { enablePriv(IPPriv); url =applet.source(); return getIPaddr(url); } (* owned by Joe, not authorized for IPPriv *) getMyIP() = appletIP(this); joe appletIP system IPPriv
Callbacks getMyIP (* owned by system *) appletIP(applet) = { enablePriv(IPPriv); url =applet.source(); return getIPaddr(url); } (* owned by Joe, not authorized for IPPriv *) getMyIP() = appletIP(this); joe appletIP system IPPriv getIPaddr system
Callbacks getMyIP (* owned by system *) appletIP(applet) = { enablePriv(IPPriv); url =applet.source(); return getIPaddr(url); } (* owned by Joe, not authorized for IPPriv *) getMyIP() = appletIP(this); joe appletIP system IPPriv success getIPaddr system
A Static Approach Our thesis: types can statically enforce the Java security model. • Unsafe programs rejected at compile time • Need for runtime checks eliminated • Types are a declaritive form of security policy expression and enforcement
Security Type Examples (* privPrint needs PrintPriv *) privPrint : file -{PrintPriv}-> unit (* PrintPriv in AccessCreds(Joe) *) foreignProg : unit -{PrintPriv}-> t (* PrintPriv not in AccessCreds(Joe) *) foreignProg : *ERROR*, cannot be typed
Security Type Examples (* enables SomePriv for parameter f *) privWrap(f) = {enablePriv(SomePriv); f(); } privWrap : (unit -{SomePriv}-> unit) -{}-> unit
Subtyping Security Types • With monotypes, subtypes allow typing of more safe programs: • privWrapcan safely use the identity function id, soprivWrap(id)should be typable id :unit -{}-> unit privWrap : (unit -{SomePriv}-> unit) -{}-> unit
Security requirements may safely be overestimated Subtyping Security Types P C t1’<: t1, t2 <: t2’ P’ u (fnlt) C t1-P-> t2 <: t1’-P’-> t2’ unit -{}-> unit <: unit -{SomePriv}-> unit privWrap(id) : unit
Security Type Judgements G, P, p e : t {p} P u (checkpriv) G, P, p checkPriv p for e : t
Security Type Judgements G, P, p e : t {p} P u (checkpriv) G, P, p checkPriv p for e : t P’ G, P, p e : t’ t G, P, p e’ : t’ P’ P u (appl) G, P, p ee’ : t
Security Type Judgements G, P, p e : t {p} P u (checkpriv) G, P, p checkPriv p for e : t P’ G, P, p e : t’ t G, P, p e’ : t’ P’ P u (appl) G, P, p ee’ : t {p} G, P u{p}, p e : t A(p) u (enablepriv) enablePriv p for e : t G, P, p
Formal Properties of the System • Stack Inspection is modeled in a language with well-defined operational semantics: S, A e v S ::= (p, P) :: S’ (secstacks) Unsafe expressions reduce to secfail: S, A e secfail
Formal Properties of the System • We prove subject reduction and type safety results for the system • Well-typed programs are not unsafe. • We prove soundness and completeness results for a type inference algorithm • type system can be transparently layered over existing system
Type Inference • Algorithm is standard constraint inference, plus a new constraint satisfiability check: • Privilege sets may contain variables • Privilege set variable constraints may be recursive • Satisfiability check is novel, efficient; correctness is proved
Incompleteness of the System • Java privileges are first-class • Java programs can conditionally branch on presence/absence of privileges • Paramaterized privileges, e.g.: fileRead(filename) • Dynamic access control lists
Work in Progress • Extend type systemto accurately type privilege tests • Polymorphism • More sophisticated language features (Java features, modules) • Readability of types
Conclusion • Java security model is sound, but dynamic checks impose penalties • Types can be used to enforce the model, and eliminate these penalties • Security Types may be inferred efficiently http://www.cs.jhu.edu/~ces/work.html
Conclusion • Java security model is sound, but dynamic checks impose penalties • Types can be used to enforce the model, and eliminate these penalties • Security Types may be inferred efficiently http://www.cs.jhu.edu/~ces/work.html
Conclusion • Java security model is sound, but dynamic checks impose penalties • Types can be used to enforce the model, and eliminate these penalties • Security Types may be inferred efficiently http://www.cs.jhu.edu/~ces/work.html
Conclusion • Java security model is sound, but dynamic checks impose penalties • Types can be used to enforce the model, and eliminate these penalties • Security Types may be inferred efficiently http://www.cs.jhu.edu/~ces/work.html
Conclusion • Java security model is sound, but dynamic checks impose penalties • Types can be used to enforce the model, and eliminate these penalties • Security Types may be inferred efficiently http://www.cs.jhu.edu/~ces/work.html