Secure the Clones: Static Enforcement of Policies for Secure Object Copying OWASP Thomas Jensen and David Pichardie INRIA Rennes - Bretagne Atlantique FRANCE [email protected] Copyright © The OWASP Foundation Permission is granted to copy, distribute and/or modify this document under the terms of the OWASP License. The OWASP Foundation http://www.owasp.org jeudi 24 juin 2010 Accepting objects from strangers OWASP jeudi 24 juin 2010 2 Accepting objects from strangers package TheGood; class StoreMyHoneyPots { void main(String[] args) { OWASP jeudi 24 juin 2010 2 Accepting objects from strangers package TheGood; class StoreMyHoneyPots { void main(String[] args) { BookShelf bs = new BookShelf(); OWASP jeudi 24 juin 2010 2 Accepting objects from strangers package TheGood; package TheBad; class StoreMyHoneyPots { class BookShelf { void main(String[] args) { private Object[] content; BookShelf bs = new BookShelf(); public BookShelf() { ...; backdoor = this; } public add(Object o) { ... } public BookShelf clone() { ... } private badThings() { robAll(backdoor.content); } OWASP jeudi 24 juin 2010 2 Accepting objects from strangers private private private package TheGood; package TheBad; class StoreMyHoneyPots { class BookShelf { void main(String[] args) { private Object[] content; BookShelf bs = new BookShelf(); public BookShelf() { ...; backdoor = this; } public add(Object o) { ... } bs.add(pot1); bs.add(pot2); bs.add(pot3); public BookShelf clone() { ... } private badThings() { robAll(backdoor.content); } } } OWASP jeudi 24 juin 2010 2 Accepting objects from strangers private private private package TheGood; package TheBad; class StoreMyHoneyPots { class BookShelf { void main(String[] args) { private Object[] content; BookShelf bs = new BookShelf(); public BookShelf() { ...; backdoor = this; } public add(Object o) { ... } bs.add(pot1); bs.add(pot2); bs.add(pot3); public BookShelf clone() { ... } private badThings() { robAll(backdoor.content); } } } OWASP jeudi 24 juin 2010 2 Accepting objects from strangers private private private package TheGood; package TheBad; class StoreMyHoneyPots { class BookShelf { void main(String[] args) { private Object[] content; BookShelf bs = new BookShelf(); public BookShelf() { ...; backdoor = this; } public add(Object o) { ... } bs.add(pot1); bs.add(pot2); bs.add(pot3); public BookShelf clone() { ... } private badThings() { robAll(backdoor.content); } } } OWASP jeudi 24 juin 2010 2 Secure Coding in Java Programs are complex collections of trusted and untrusted classes. Sensitive objects may migrate from trusted parts to untrusted parts from untrusted parts to trusted parts Enhance security by copying of objects. OWASP jeudi 24 juin 2010 3 http://java.sun.com/security/seccodeguide.html Guideline 2-2 Create copies of mutable outputs If a method returns a reference to an internal mutable object, then client code may modify internal state. Therefore, copy mutable objects before returning, unless the intention is to share state. To create a copy of a trusted mutable object, call a copy constructor or clone method. OWASP jeudi 24 juin 2010 4 Clone Defense package TheGood; package TheBad; class StoreMyHoneyPots { class BookShelf { private Object[] content; void main(String[] args) { public BookShelf() { ...; backdoor = this; } BookShelf bs = new BookShelf(); bs = bs.clone(); public add(Object o) { ... } bs.add(pot1); bs.add(pot2); bs.add(pot3); public BookShelf clone() { ... } private badThings() { robAll(backdoor.content); } } } OWASP jeudi 24 juin 2010 5 Clone Defense package TheGood; package TheBad; class StoreMyHoneyPots { class BookShelf { private Object[] content; void main(String[] args) { public BookShelf() { ...; backdoor = this; } BookShelf bs = new BookShelf(); bs = bs.clone(); public add(Object o) { ... } bs.add(pot1); bs.add(pot2); bs.add(pot3); public BookShelf clone() { ... } private badThings() { robAll(backdoor.content); } } } OWASP jeudi 24 juin 2010 5 Clone Defense package TheGood; private package TheBad; class BookShelf { class StoreMyHoneyPots { private Object[] content; void main(String[] args) { BookShelf bs = new BookShelf(); private private public BookShelf() { ...; backdoor = this; } bs = bs.clone(); public add(Object o) { ... } bs.add(pot1); bs.add(pot2); bs.add(pot3); public BookShelf clone() { ... } private badThings() { robAll(backdoor.content); } } } OWASP jeudi 24 juin 2010 5 Copy In Java No default copy Copy methods must be provided by programmers by implementing Cloneable interface class A implements Cloneable { Object clone() {...} } or a copy constructor class A { A (A source) {...} } OWASP jeudi 24 juin 2010 6 Shallow/Deep Copy next next next va va va lu e lu e ... lu e OWASP jeudi 24 juin 2010 7 Shallow/Deep Copy next next next va va va lu e lu e ... lu e deep copy u al e v next ue l va next ue l va next ... OWASP jeudi 24 juin 2010 7 Shallow/Deep Copy next next next va va va lu e lu e ... lu e OWASP jeudi 24 juin 2010 7 Shallow/Deep Copy shallow copy next next next va va va lu e e u l va next lu e e u l va next ... lu e e u l va next ... OWASP jeudi 24 juin 2010 7 Shallow/Deep Copy class List { V value; List next; List(V value, List next) { this.value = value; this.next = next; } List clone() { return new List(value, (next==null ? null : next.clone())); } List deepClone() { return new List((V) value.clone(), (next==null ? null : next.deepClone())); } } jeudi 24 juin 2010 OWASP 8 Copy in Java Sub-classing and overriding complicate matters This field is final but content is mutable public class CopyOutput { private final java.util.Date date; ... public java.util.Date getDate() { return (java.util.Date)date.clone(); } } OWASP jeudi 24 juin 2010 9 Copy in Java Sub-classing and overriding complicate matters This field is final but content is mutable public class CopyOutput { Does it really private final java.util.Date date; ... perform a copy ? public java.util.Date getDate() { return (java.util.Date)date.clone(); } } It may call an overridden version of Date.clone() ! OWASP jeudi 24 juin 2010 9 What we want: Copy policy language expressive simple and modular compatible with subclassing and method overriding with semantic foundations Enforcement mechanism sound precise enough for «reasonable» clone methods compatible with class-based bytecode verification fast enough to be used at class loading time can handle legacy code OWASP jeudi 24 juin 2010 10 Secure Cloning A new annotation system for expressing copy policies Enforcement: a type system that enforces non-sharing but does not guarantee exact copy Copy policies can be checked in the presence of overriding. accumulate constraints on "deep"-ness of the copy OWASP jeudi 24 juin 2010 11 Shallow/Deep Copy class List { V value; List next; List(V value, List next) { this.value = value; this.next = next; } Copy signature @Copy(default){ @Shallow value; @Deep(default) next;} List clone() { return new List(value, (next==null ? null : next.clone())); } } OWASP jeudi 24 juin 2010 12 Shallow/Deep Copy class List { @Shallow V value; @Deep List next; Default copy signature List(V value, List next) { this.value = value; this.next = next; } @Copy List clone() { return new List(value, (next==null ? null : next.clone())); } } OWASP jeudi 24 juin 2010 13 Shallow/Deep Copy class List { @Shallow V value; @Deep List next; Default copy signature List(V value, List next) { this.value = value; this.next = next; } @Copy List clone() { return new List(value, (next==null ? null : next.clone())); } Explicit copy signature @Copy(List.Deep){ @Deep value; @Deep(List.Deep) next;} List deepClone() { return new List((V) value.clone(), (next==null ? null : next.deepClone())); } } jeudi 24 juin 2010 OWASP 14 Copy Policy Grammar τ ∈ Policy af ∈ AnnotField a ∈ Annot ::= Copy(X){af ; . . . ; af } ::= a f ::= Shallow | Deep(X) A heap cell reachable from the result of a call m(...) by following only fields marked Deep is not reachable from any local variable. OWASP jeudi 24 juin 2010 15 Observations Enforcing non-sharing of dynamically allocated structure is complex Copy methods are generally simple (and sometimes only straight-line code) We adopt a local shape analysis technique OWASP jeudi 24 juin 2010 16 (Our) Shape Analysis We abstract the memory by a shape graph e lu va e lu va ! xt ne x next ! OWASP jeudi 24 juin 2010 17 (Our) Shape Analysis We abstract the memory by a shape graph must overapproximate all ingoing edges may represent any sub-graph without back edges towards blue nodes ! e lu va e lu va represents at most one cell next xt x ne local var may represent several cells ! OWASP jeudi 24 juin 2010 17 (Our) Shape Analysis Concrete memory x We abstract the memory by a shape graph next next next va va va lu e lu e lu e null . .. s r p re t n e es e lu va e lu va ! xt ne x next ! OWASP jeudi 24 juin 2010 17 (Our) Shape Analysis Concrete memory x We abstract the memory by a shape graph r ep va va va e lu e lu e next . .. xt lu e next null va lu . .. e represents e lu va ! OWASP jeudi 24 juin 2010 null y va ne e lu va ! next s t n e es x x next lu r next next 17 (Our) Shape Analysis Concrete memory x We abstract the memory by a shape graph r ep va va va e lu e lu e next . .. va xt lu e next null va lu . .. e represents pres ent t ! n’t re x ne e lu va does x next va lu e snoop va lu e OWASP jeudi 24 juin 2010 null y ne e lu va ! next s t n e es x x next lu r next next 17 (Our) Shape Analysis Concrete memory x We abstract the memory by a shape graph va va va e lu e null lu e . .. r ep y next ne va xt lu e next null va lu . .. e represents next pres ! ent x next va lu e snoop va lu e s represent e lu va ! n’t re t ! does x ne e lu va e lu va x next s t n e es x x next lu r next next jeudi 24 juin 2010 ! OWASP 17 Shape Graphs: formal notation n1 n2 e lu va e lu va ! xt ne x next ! Γ =[ x !→ n1 , y !→ #] ∆ = [(n1 , next) !→ n2 , (n2 , next) !→ n2 , (n1 , value) !→ #, (n2 , value) !→ # ] Θ = {n1 } OWASP jeudi 24 juin 2010 18 How to check a copying method m ? 1.Extract a graph type from a copy policy ne class List { @Shallow V value; @Deep List next; @Copy Object clone() {...} } copy policy res xt extraction next val val ue ue ! ! shape graph 2.A type system checks if m satisfies the graph type 3.Type inference is required at join points 4.Needs a subtyping relation ! on graph types OWASP jeudi 24 juin 2010 19 Typing Rules ... x ... y x y Γ, ∆, Θ ! x :=y : Γ[x "→ Γ(y)], ∆, Θ OWASP jeudi 24 juin 2010 20 Typing Rules f n! n x n y f x n! y Γ(x) = n n ∈ Θ Γ(y) = n! Γ, ∆, Θ " x .f :=y : Γ, ∆[(n, f ) #→ n! ], Θ OWASP jeudi 24 juin 2010 21 Case Study java.util.LinkedList OWASP jeudi 24 juin 2010 22 public class LinkedList<E> implements Cloneable { private Entry<E> header; } private static class Entry<E> { E element; Entry<E> next; Entry<E> previous; } next next next header el e m e nt previous el e m e nt previous e e m le nt previous t n e m e l e OWASP jeudi 24 juin 2010 23 public class LinkedList<E> implements Cloneable { private @Deep Entry<E> header; } private static class Entry<E> { @Shallow E element; @Deep Entry<E> next; @Deep Entry<E> previous; } next next next header el e m e nt previous el e m e nt previous e e m le nt previous t n e m e l e OWASP jeudi 24 juin 2010 24 public Object clone() { LinkedList<E> clone = null; clone = (LinkedList<E>) super.clone(); clone.header = new Entry<E>; clone.header.next = clone.header.previous = clone.header; for (Entry<E> e = this.header.next; e != this.header; e = e.next) { Entry<E> newEntry = new Entry<E>; newEntry.element = e.element; newEntry.next = clone.header; newEntry.previous = clone.header.previous; newEntry.previous.next = newEntry; newEntry.next.previous = newEntry; } return clone; } OWASP jeudi 24 juin 2010 25 public Object clone() { LinkedList<E> clone = null; clone ⊥ clone = (LinkedList<E>) super.clone(); clone.header = new Entry<E>; clone.header.next = clone.header.previous = clone.header; for (Entry<E> e = this.header.next; e != this.header; e = e.next) { Entry<E> newEntry = new Entry<E>; newEntry.element = e.element; newEntry.next = clone.header; newEntry.previous = clone.header.previous; newEntry.previous.next = newEntry; newEntry.next.previous = newEntry; } return clone; } jeudi 24 juin 2010 OWASP 26 public Object clone() { LinkedList<E> clone = null; clone = (LinkedList<E>) super.clone(); header clone ! clone.header = new Entry<E>; clone.header.next = clone.header.previous = clone.header; for (Entry<E> e = this.header.next; e != this.header; e = e.next) { Entry<E> newEntry = new Entry<E>; newEntry.element = e.element; newEntry.next = clone.header; newEntry.previous = clone.header.previous; newEntry.previous.next = newEntry; newEntry.next.previous = newEntry; } return clone; } jeudi 24 juin 2010 OWASP 27 public Object clone() { LinkedList<E> clone = null; clone = (LinkedList<E>) super.clone(); s ⊥ ou i v e clone.header = new Entry<E>; header clone pr element next ⊥ ⊥ clone.header.next = clone.header.previous = clone.header; for (Entry<E> e = this.header.next; e != this.header; e = e.next) { Entry<E> newEntry = new Entry<E>; newEntry.element = e.element; newEntry.next = clone.header; newEntry.previous = clone.header.previous; newEntry.previous.next = newEntry; newEntry.next.previous = newEntry; } return clone; } jeudi 24 juin 2010 OWASP 28 public Object clone() { LinkedList<E> clone = null; clone = (LinkedList<E>) super.clone(); clone.header = new Entry<E>; clone.header.next = clone.header.previous = clone.header; pr ev header clone io us element nex ⊥ t for (Entry<E> e = this.header.next; e != this.header; e = e.next) { Entry<E> newEntry = new Entry<E>; newEntry.element = e.element; newEntry.next = clone.header; newEntry.previous = clone.header.previous; newEntry.previous.next = newEntry; newEntry.next.previous = newEntry; } return clone; } jeudi 24 juin 2010 OWASP 29 public Object clone() { LinkedList<E> clone = null; clone = (LinkedList<E>) super.clone(); clone.header = new Entry<E>; clone.header.next = clone.header.previous = clone.header; pr ev i header clone ou s element ⊥ t nex for (Entry<E> e = this.header.next; e != this.header; e = e.next) { Entry<E> newEntry = new Entry<E>; newEntry.element = e.element; newEntry.next = clone.header; newEntry.previous = clone.header.previous; newEntry.previous.next = newEntry; newEntry.next.previous = newEntry; } return clone; } jeudi 24 juin 2010 OWASP 30 public Object clone() { LinkedList<E> clone = null; clone = (LinkedList<E>) super.clone(); clone.header = new Entry<E>; clone.header.next = clone.header.previous = clone.header; pr pr ev ev i header clone ou s element ⊥ header clone t nex io us element nex t for (Entry<E> e = this.header.next; e != this.header; e = e.next) { Entry<E> newEntry = new Entry<E>; newEntry.element = e.element; newEntry.next = clone.header; newEntry.previous = clone.header.previous; newEntry.previous.next = newEntry; newEntry.next.previous = newEntry; } return clone; } jeudi 24 juin 2010 OWASP 30 ! public Object clone() { LinkedList<E> clone = null; clone = (LinkedList<E>) super.clone(); clone.header = new Entry<E>; clone.header.next = clone.header.previous = clone.header; pr pr ev ev i header clone ou s element t nex ⊥ ! header clone io us element nex t for (Entry<E> e = this.header.next; e != this.header; e = e.next) { Entry<E> newEntry = new Entry<E>; newEntry.element = e.element; newEntry.next = clone.header; newEntry.previous = clone.header.previous; newEntry.previous.next = newEntry; newEntry.next.previous = newEntry; } return clone; } jeudi 24 juin 2010 OWASP 30 ! public Object clone() { LinkedList<E> clone = null; clone = (LinkedList<E>) super.clone(); clone.header = new Entry<E>; clone.header.next = clone.header.previous = clone.header; pr ev header clone io us element nex t for (Entry<E> e = this.header.next; e != this.header; e = e.next) { Entry<E> newEntry = new Entry<E>; newEntry.element = e.element; newEntry.next = clone.header; newEntry.previous = clone.header.previous; newEntry.previous.next = newEntry; newEntry.next.previous = newEntry; } return clone; } jeudi 24 juin 2010 OWASP 30 ! public Object clone() { LinkedList<E> clone = null; clone = (LinkedList<E>) super.clone(); clone.header = new Entry<E>; clone.header.next = clone.header.previous = clone.header; for (Entry<E> e = this.header.next; e != this.header; e = e.next) { Entry<E> newEntry = new Entry<E>; newEntry pr ev i s u o ⊥ evi ou s element header clone ! t nex pr element next ⊥ ⊥ e ! newEntry.element = e.element; newEntry.next = clone.header; newEntry.previous = clone.header.previous; newEntry.previous.next = newEntry; newEntry.next.previous = newEntry; } return clone; } jeudi 24 juin 2010 OWASP 31 public Object clone() { LinkedList<E> clone = null; clone = (LinkedList<E>) super.clone(); clone.header = new Entry<E>; clone.header.next = clone.header.previous = clone.header; for (Entry<E> e = this.header.next; e != this.header; e = e.next) { Entry<E> newEntry = new Entry<E>; newEntry.element = e.element; newEntry pr ev i s ou i v e ou s element header clone ! t nex pr element next ⊥ ! ⊥ e ! newEntry.next = clone.header; newEntry.previous = clone.header.previous; newEntry.previous.next = newEntry; newEntry.next.previous = newEntry; } return clone; } jeudi 24 juin 2010 OWASP 32 public Object clone() { LinkedList<E> clone = null; clone = (LinkedList<E>) super.clone(); clone.header = new Entry<E>; clone.header.next = clone.header.previous = clone.header; for (Entry<E> e = this.header.next; e != this.header; e = e.next) { Entry<E> newEntry = new Entry<E>; newEntry.element = e.element; newEntry.next = clone.header; newEntry pr ev i ou header t en em el clone s next s ⊥ ou i v e pr element ! e ! t nex ! newEntry.previous = clone.header.previous; newEntry.previous.next = newEntry; newEntry.next.previous = newEntry; } return clone; } jeudi 24 juin 2010 OWASP 33 public Object clone() { LinkedList<E> clone = null; clone = (LinkedList<E>) super.clone(); clone.header = new Entry<E>; clone.header.next = clone.header.previous = clone.header; for (Entry<E> e = this.header.next; e != this.header; e = e.next) { Entry<E> newEntry = new Entry<E>; newEntry.element = e.element; newEntry.next = clone.header; newEntry.previous = clone.header.previous; newEntry pr ev i ou header s next element clone xt previous nt e em el ne newEntry.previous.next = newEntry; ! e ! ! newEntry.next.previous = newEntry; } return clone; } jeudi 24 juin 2010 OWASP 34 public Object clone() { LinkedList<E> clone = null; clone = (LinkedList<E>) super.clone(); clone.header = new Entry<E>; clone.header.next = clone.header.previous = clone.header; for (Entry<E> e = this.header.next; e != this.header; e = e.next) { Entry<E> newEntry = new Entry<E>; newEntry.element = e.element; newEntry.next = clone.header; newEntry.previous = clone.header.previous; newEntry.previous.next = newEntry; pr ev i ou s element header clone newEntry } ! e ! t x ne ! = newEntry; newEntry.next.previous return clone; } jeudi 24 juin 2010 OWASP 35 public Object clone() { LinkedList<E> clone = null; clone = (LinkedList<E>) super.clone(); clone.header = new Entry<E>; clone.header.next = clone.header.previous = clone.header; for (Entry<E> e = this.header.next; e != this.header; e = e.next) { Entry<E> newEntry = new Entry<E>; newEntry.element = e.element; newEntry.next = clone.header; newEntry.previous = clone.header.previous; newEntry.previous.next = newEntry; newEntry.next.previous = newEntry; pr ev i ou s element header clone newEntry ! e ! t x ne } return clone; } jeudi 24 juin 2010 OWASP 36 public Object clone() { LinkedList<E> clone = null; clone = (LinkedList<E>) super.clone(); clone.header = new Entry<E>; clone.header.next = clone.header.previous = clone.header; pr ev header clone io us element x ne ! t for (Entry<E> e = this.header.next; e != this.header; e = e.next) { ... pr ev i ou s element header clone newEntry } return clone; } jeudi 24 juin 2010 ! e ! t x ne ! OWASP 37 public Object clone() { LinkedList<E> clone = null; clone = (LinkedList<E>) super.clone(); clone.header = new Entry<E>; clone.header.next = clone.header.previous = clone.header; pr ev header clone io us element x ne ! t ! for (Entry<E> e = this.header.next; e != this.header; e = e.next) { ... pr ev i ou s element header clone newEntry } return clone; } jeudi 24 juin 2010 ! e ! t x ne ! OWASP 37 public Object clone() { LinkedList<E> clone = null; clone = (LinkedList<E>) super.clone(); clone.header = new Entry<E>; clone.header.next = clone.header.previous = clone.header; for (Entry<E> e = this.header.next; e != this.header; e = e.next) { Entry<E> newEntry = new Entry<E>; newEntry.element = e.element; newEntry.next = clone.header; newEntry.previous = clone.header.previous; newEntry.previous.next = newEntry; newEntry.next.previous = newEntry; } return clone; pr } ev i ou s element header clone t x ne ! ! OWASP jeudi 24 juin 2010 38 Experiments Tested on GNU ClassPath 285 clone methods ... res 253 return at least ! 78 methods produced more complex graphs Some case studies on more complex copy policies java.lang.LinkedList verification of «deep clone» in gnu.xml.Stylesheet OWASP jeudi 24 juin 2010 39 The JAVASEC project Commissioned by the French National Agency for Security of Information systems Analysis of security of Java and JVMs Language features Secure programming guidelines Strengthening of a JVM extended byte code verification secure memory Evaluation/certification of secure JVM http://www.ssi.gouv.fr/site_article226.html OWASP jeudi 24 juin 2010 40 Conclusions Cloning was left to the programmer a source of mis-understanding no semantics Declare copy policies for copy methods Check copy policies with a type system Implemented Formalized OWASP jeudi 24 juin 2010 41
© Copyright 2026 Paperzz