290 likes | 444 Views
Security Checking. Wishnu Prasetya wishnu@cs.uu.nl www.cs.uu.nl/docs/vakken/pv. Plan. Extended static checking Credential model Security testing Exception. Extended Static Checking (ESC). if nothing else known, then true as pre- cond.
E N D
Security Checking Wishnu Prasetya wishnu@cs.uu.nl www.cs.uu.nl/docs/vakken/pv
Plan • Extended static checking • Credential model • Security testing • Exception
Extended Static Checking (ESC) if nothing else known, then true as pre-cond • To check some generic correctness properties, e.g. that the program won’t crash due to division by zero, access to an array with an illegal index, null dereference, etc. • Rely on auto-annotation. tax(rate, income | tax) { if(income 10000) tax := 0 ; if (income 20000) tax := income / rate.low ; tax := tax + income / rate.high ; } assertrate.low 0 assertrate.high 0 { true }
Some notes on ESC • We still have to deal with loops • For automation, you may favor the whilek approach, but this approach is not sound. • There may be some crashes that we won’t be able to detect. • Is this bad?
Security • Security: access to certain variables or methods may require certain credentials. • Privacy : an object may have a set of “owners”, and should only be accessed by these owners. • Unifying concept: a credential specifies a set of users. • c d means that d has at least the same level of access as c. • Example: root , {u}, and • More abstractly, assume a security domain (C,,), complete lattice.
Expressing security policy in GCL • Global variables cred0 and cred • cred0 can only be assigned once. • cred cred0 should hold, at all time. • Variables can declare the required credentialvar x cydzin ... end • This requirement is static. • Information can only flow towards variables with the same or lower credentials. • Note that not all kinds of security policy can be expressed with these constructs.
Example • Suppose var x cydzin ... • Considercred:=e ; z:=x+yAnnotated to:assert e cred0 ; cred:=e ; assert c cred ;assert d c ; assert d z:=x+y
Dealing with branches • Consider: if x=0 then x:=y else z:=0 { Q } • After annotation:if x=0 then { assertccred ; x := y } else { assertdcred ; z := 0 } • the wlp :(x=0 (ccred /\ Q[y/x])) /\ (x0 dcred /\ Q[0/z]) • Doubling the formula size Can we simplify?
Case reduction • (a b) /\ (a c) b /\ cReducing wlp like this is sound, but in most cases this is too strong. • There exists an f wheref ((a b) /\ (a b) b /\ c)A realistic f ?
Reducing branch, with security goals • Recall the wlp : (x=0 (ccred /\ Q[y/x])) /\ (x0 dcred /\ Q[0/z]) • Consider dcred as the post-condition. The wlp would then be:(x=0 ccred /\ dcred) /\ (x0 dcred) • Is it reasonable to apply case-reduction on this?
Dealing with loops • [while]k unfolding is too restrictive • An unsound approach in not acceptable. • while y>0 do {x := x+y ; y := y−1} {ccred} • Annotatedto: assert c cred ; while y > 0 do { assert c cred ; x := x+y ; assert c cred ; y := y−1 ; assert c cred ; } W0 = true W1 = (y>0 /\ wlpbody W0) \/ (y0 /\ ccred) = (y>0 /\ ccred) \/ (y0 /\ ccred) = ccred W2 = ... fix point! Nice.
Ok, how about this? • A slightly different post-condition while y > 0 do { assert c cred ; x := x+y ; assert c cred ; y := y−1 ; assert c cred ; } W0 = true W1 = (y>0 /\ ccred) \/ (y0 /\ dcred) W2 = (y>1 /\ ccred) \/ (y=1 /\ ccred /\ dcred) \/ (y0 /\ dcred) .... does not terminate d cred
You have to fall back... • Need a proposal for an invariant : ccred /\ dcred • Can such a proposal be automated ? while y > 0 do { assert c cred ; x := x+y ; assert c cred ; y := y−1 ; assert c cred ; } d cred
A loop that does something to credentials • while y > 0 do {cred := cred+1 ; y := y−1} { ccred } • Annotated to: W0 = true W1 = (y>0 /\ cred+1cred0 /\ c cred+1) \/ (y0 /\ ccred) = ((y>0 /\ c cred+1) \/ (y0 /\ ccred)) /\ (y>0 cred+1cred0) W2 = ((y>0 /\ c cred+1) \/ (y0 /\ ccred)) /\ (y>1 cred+2cred0) /\ (y=1 cred+1cred0) ... does not terminate assert c cred ; while y > 0 do { assert cred+1 cred0 ; cred := cred+1 ; assert c cred ; y := y−1 ; assert c cred ; }
Need a proposal again... • We can try : cred+y cred0 /\ ccred • Or even: cred+y cred0 /\ ((y>0 /\ c cred+1) \/ (y0 /\ ccred)) assert c cred ; while y > 0 do { assert cred+1 cred0 ; cred := cred+1 ; assert c cred ; y := y−1 ; assert c cred ; } { c cred }
What do we do with loops like the previous one? • Maybe we only have a few • Heuristics to statically analyze the program, and propose invariants • Dynamically infer proposals from logs
Unauthorized use of resource • Represent secured resources as objects, that can only be accessed through their methods. • Programs/Methods can now declare required credential: e Pr(x | r ) body • Annotate calls to Pr accordingly. • Method’s credential is static; so this is just a simple extension of the scheme we have so far. • How about dynamic binding ?
Input injection attack • Use of external components is security risk. Imagine Pr(x), where x is a user input and inside it sends a query to a backend DB engine. • A program cannot naively trust its user’s input. • Typical approach is to sanitize inputs. query := "SELECT * FROM users” + “WHERE name =’" + userName + "’;" "’ or ’1’=’1"
Modeling sanitation • Introduce function sanitize(expr) • We prefer to treat this function abstractly uninterpreted function. • But the programmer has to specify, to what credential the result would be appropriate. • syntax: sanitize(expr,c) • It will be the programmer’s responsibility to make sure that the credential claim is met. • our logic will check over the consequences of that.
Examples • y := x+1The resulting wlp will be unsatisfiable the program is definitely not safe the logic detected it, yay! • y := sanitize(x,c)+1 { cd } • But what if we want to prove this post-cond: cd /\ y=0Losing information due to the taken abstraction...
Dealing with data privacy • Each object o now has a field priv containing the ‘locally’ minimum credential to access the object. • net(o) • priv(o) = { p.priv | p net(o) } • Assignment like o.f := 9 is now annotated to:assertpriv(o)cred ; o.f := 9
How about objects restructuring? • How about n.child := o {priv(p) cred-1 } • Annotated to: assertpriv(n)cred ∧ priv(o)cred ; n.g := o • This wlp ? priv(n)cred ∧ priv(o)cred ∧ priv(p) cred-1 • But the assignment may potentially affect priv(p) ! • Ok, there are three cases, before the assignment : • p was not in net(o) nor net(n) • p was in net(o) // similary if it was in net(n)
Exception • Exception introduces non-standard flow of execution, which are often error prone; thus also security prone. • The problem is, exception can be thrown from many points in the program, basically exploding the goals to solve for verification. • But first ... how to deal with exception in Hoare logic / wlp ?
Exception • Introduce a global variable exc : bool, initially false • raise sets this variable to true • entering a handler reset it to false • A state where exc is true, is an ‘exceptional’ state, else it is a normal state. • Note that multiple exception types can be encoded. • The obvious:wlpraise Q = Q[true/exc]
Assignments and guards • In GCL evaluating an expression does not crash; so you have to properly ‘annotate’ the expression to model crashes. E.g. : x := a[k]/yshould be transformed to e.g. :if k<0 \/ k#a thenraise ; // alternatively use assert if y=0 thenraise ; // alternatively use assert x := a[k]/y ; • Similar situation with ite and loop guard.s
Sequential composition is now ugly • S1 ; S2 S1; ifexcthen skip else S2 • wlp(S1 ; S2) Q =wlp S1 (exc /\ Q) \/wlp S1 (exc /\ wlp S2 Q) • Now “;” also doubles the formula • However, you can statically check if S1 contains raise, if it does not, we don’t do the expansion. • while g do S while g /\ inc do S
exception handler • S ! H S ; ifexcthen{ exc:=false ; H } else skip • wlp(S ! H) Q =wlp S (exc /\ Q) \/wlp S (exc /\ ((wlp H Q)[false/exc])) • Two scenarios • S manages to terminate normally H is not executed • S throws an exception control goes to H
Summary • Static Security Checking can be done, almost automatically. • Require critical variables or classes to declare needed credential • Rely on annotating transformation • Data privacy checking is much harder • Calculating wlp of loops can be challenging, but it looks like it can be mitigated • Branches explode the formula, exception make its even worse; some heuristic to reduce the formula on the fly would be nice; but do watch for the overhead.