information-flow security in haskell
DESCRIPTION
Information-Flow Security in Haskell. Alejandro Russo [email protected]. Advance Functional Programming Guest Lecture, February 1 6 th, 200 9. Introduction. Computer systems usually handles confidential information Credit card numbers, passwords, medical files, etc Mobile phones? - PowerPoint PPT PresentationTRANSCRIPT
1
Information-Flow Security in Haskell
Alejandro Russo [email protected]
Advance Functional ProgrammingGuest Lecture, February 16th, 2009
Introduction
• Computer systems usually handles confidential information
– Credit card numbers, passwords, medical files, etc
• Mobile phones?
• How can programs preserve confidentiality of data ?
Linux Login Authentication
• /etc/passwd
• /etc/shadow
bjorn:x:1003:100::/home/andrei:/bin/bashhana:x:500:100::/home/tsa:josef:x:1006:100::/home/john:/bin/bash
bjorn:$1$0ID5oZxB$0tdKR1VQWWQlkJR1Uj7na0:13397:0:99999:7:::hana:$1$.28fO/M9$aaNMN4SWEKZiGPYoEq9996:13460:0:::::0josef:$1$UP1uD.28$hi3vYEa20.zgWYNVN/Lq81:13539:0:99999:7:::
Linux Shadow Password HOWTO: Adding shadow support to a C program
Adding shadow support to a program is actually fairly straightforward. The only problem is that the program must be run by root (or SUID root) in order for the the program to be able to access the /etc/shadow file.
Linux Login Authentication
• Security problems?
• Passwords can be stolen– It is only necessary to obtain
root access• Trojan horses• Buffer overflow attacks• Etc...
Linux Login Authentication
• Linux provides an API to access /etc/shadow
#ifdef HAS_SHADOW #include <shadow.h> #include <shadow/pwauth.h> #endif
• /etc/shadow can be accessed not only by the API– Let assume the opposite
More graphically
Storage for passwords
API
API called by any user API called only with root
privileges
Confidentiality of passwords NO NOaccess control is not enough!
Demo
Language-based Security
• Analyzing the code of the whole system– Confidentiality, Integrity,
etc.
• Information-flow analysis: – How the information flow
inside programs: is there a secret “going out” of the system?
Information-Flow
• Programs have secret and public inputs and outputs, respectively
Non-interference
Information-Flow
• Programs have secret and public inputs and outputs, respectively
Leak of Information!
Information-Flow Security
• Study for ~30 years• Active research field• Compilers
– JIF (Java) 2001-2009• Cornell University
– FlowCaml (ML) 2002• INRIA (not actively
developed)
• Impact on practice– Limited!
Why Haskell?
• Pure language
– No side-effects
– Side-effects reflected in types (IO, etc)
• Strong type system
– Cannot ”cheat”
Examples
f (c, i) = ( chr(ord c + i), i)
f :: (Char {- secret -}, Int) -> (Char {- secret -}, Int)
f (c, i) = (chr(ord c + i), chr c)
f (c, i) = (chr(ord c + 1), i+1)
f (c, i) | c > 65 = (c, 42) | otherwise = (c, i)
Secure
Insecure
Insecure
Secure
Simple security API
data SecH a – abstract
instance Functor SecHinstance Monad SecH
• Once inside the monad, you cannot go out!!
f :: (SecH Char, Int) -> (SecH Char, Int)
• Termination-insensitive security
• Termination-sensitive.. Agda?
Revised examples
f (sc,i) = (do c <- sc return chr(ord c+i), i)
f ::(SecH Char, Int) -> (SecH Char, Int)
f (c, i) = (chr(ord c + i), chr c)
Type checks!
Insecure
f (c, i) = ( chr(ord c + i), i) Secure
f (sc, i) = (…, do c <- sc return (chr c) )
Doesn’t type checks!
Security guarantee
Type checks!
Secure
Security latticedata Sec s a -- abstract
data H = H -- abstractdata L = L -- public
class Less sL sH where lesser :: sL -> sH -> ()
up :: Less sL sH => Sec sL a -> Sec sH a
instance Less L Hinstance Less L Linstance Less H H
Sec H a ~= SecH aSec L a ~= a
H
L • •
•
Arquitecture
Code of the library
Haskell Libraries
Attacker/ Untrusted
Code
Trusted Code
Secure Interface
(SecLib.hs)
Safe Haskell Libraries
unsafePerformIO, Exceptions, etc.
~400 LOC
What about IO?
• IO Features
– References
– Files
– Stdin/Stdout
• In this talk only files
Secure side-effects
What about trying to do side-effects inside of the security monad?
SecH (IO a) Secure
We don’t know!
Another monad?
Insecure
Extended security API
data SecIO s a –- abstract
value :: Sec s a -> SecIO s a
data File s -- abstract
readFileSecIO :: File s’ -> SecIO s (Sec s’String)
writeFileSecIO :: File s -> String -> SecIO s ()
run :: SecIO s a -> IO (Sec s a)
-Write to level s or higher-Produce a value at level s
instance Functor SecIOinstance Monad SecIO
Side effects escape from SecIO!
Little quiz for trusted code’s programmers
IO (Sec H a)
Secure
Sec H ( IO (Sec L a) )
Insecure
SecIO L Int
SecIO L (IO () )
Secure
Insecure Attacker/ Untrusted
Code
Trusted Code
Login Authentication
• We have the following API to the shadow file
data Spwd = Spwd { uid :: UID, cypher :: Cypher }
getSpwdName :: Name -> IO (Maybe Spwd)
putSpwd :: Spwd -> IO ( )
• Can we rewrite it ?– To avoid passwords being stolen
Secure API?
• Can we implement an API that preserves the confidentiality of passwords?– Let’s use our Sec, SecIO, etc.– Let’s see the types again.
data Spwd = Spwd { uid :: UID, cypher :: Cypher }
getSpwdName :: Name -> IO
putSpwd ::
(Maybe (Sec H Spwd) )
Sec H Spwd -> IO (Sec H ( ) )
(Maybe Spwd)
Spwd -> IO ( )
Auxiliaries functions
• do s <- readFile path_Shadow
• (s == s) `seq` return (read s :: [(UID, Cypher)])path_Passwd :: FilePath
path_Passwd = “/etc/passwd“
parseSpwd :: IOparseSpwd =
parsePwd :: IO ([(Name, UID)])parsePwd = do s <- readFile path_Passwd (s == s) `seq` return (read s :: [(Name, UID)])
path_Shadow :: File Hpath_Shadow = highF -- Like /etc/shadow.. (access only by API)
( Sec H [(UID, Cypher)] )
run ( do sec <- readFile path_Shadow -- sec :: Sec H String s <- value sec -- s :: String (s == s) `seq` return (read s :: [(UID, Cypher)]))
API: Getting a password
getSpwdName :: Name -> IO (Maybe (Sec H Spwd) )getSpwdName user = do sec_pwds <- parseSpwd -- sec_pwds :: Sec H [(UID, Cypher)] users <- parsePwd -- users :: ([(Name, UID)] case lookup user users of Nothing -> return Nothing Just uid’ -> return $ Just $ case lookup uid’ ps of
Nothing -> error “not possible” Just c -> Spwd { uid = uid’ , cypher = c})
( \ps ->
`fmap` sec_pwds
API: Setting a password
putSpwd :: putSpwd pwd = do sec_pwds <- parseSpwd -- sec_pwds :: Sec H [(UID, Cypher)]
Sec H Spwd -> IO (Sec H ( ) )
let (id, c) = (uid pwd, cypher pwd) (ts,ds) = span (\(u,_) -> u /= id ) pwds updated = if null ds then ts++[(id,c)] else ts++[(id,c)]++(tail ds)
let secio = do pwds <- value sec_pwds -- pwds :: [(UID, Cypher)]
writeFileSecIO path_Shadow (show updated)
run secio
More graphically
Storage for passwords
API
Secure API
• Security problems of our secure API?
• Passwords can be stolen?– No!
• Trojans? Buffer overflows?
– No need to be root to use the API – No need to perform SIUD to use
the API
• Can we implement a login program?
Declassification
Declassification
• Login program: it is necessary to leak information that depends on secrets• pwd == input
• Dimensions and principles of declassificaiton [Sabelfeld and Sands, 06]• What information can be leak?• When can information be leaked?• Where in the program is safe to leak information?• Who can leak information?
• How to be certain that our programs leak what they are supposed to leak?
Declassification in the Library
• Our library should be able to handle different kind of declassificaiton policies
• Policies are programs!– Trusted users of the library
implement them– Controlled at run-time
• A module defines combinators for different declassification policies (what, when, who)
• In the talk: what
Trusted Code
Escape hatches
• Declassification is performed by functions– Terminology: escape hatches [Sabelfeld and Myers,
2004]
• In our library:
• Example: checking password
type Hatch sH sL a b = Sec sH a -> Sec sL b
hatch :: (a -> b) -> Hatch sH sL a b –- hidden
check :: Hatch H L (String,Passwd) Boolcheck = hatch (\(input,pwd) -> pwd == input)
monomorphic
Escape hatches
• We want to restrict capabilities of escape hatches
type Hatch sH sL a b = Sec sH a -> IO (Maybe (Sec sL b))
internal state
may fail
Declassification combinators
-- Restricting ”what” (how often)nTimes :: Int -> Hatch sH sL a b -> IO (Hatch sH sL a b)
-- Examplematch = nTimes 3 (hatch (\(secret,pwd) -> secret == pwd))
• Other combinators in the library...– who, when
• Possible to combine them and create ”complex” policies for declassification!
Login Program (Code)import IOimport SpwdDataimport Spwd
loginMain = do welcome u <- username login 3 u
welcome = putStrLn "This is ged node. Welcome!"
username = do putStr "ged login: " getLine
login 0 _ = return ()login n u = do putStr "Password:" pwd <- getLine src <- getSpwdName u case src of Nothing -> putStrLn "Invalid user!" Just p -> check p pwd n u
check p pwd n u = do Just acc <- match ((\s -> (s, pwd)) `fmap` p) if acc then putStrLn "Launching shell..." else do putStrLn "Invalid login!"
login (n-1) u
(Maybe (Sec H Spwd) )
(Sec H Spwd)
Further details
• Login program using the secure API + declassification
• Paper about the library– Authors: Russo, Claessen, Hughes
– Haskell Symposium ’08
– Google: Alejandro Russohttp://www.cs.chalmers.se/~russo/
Conclusions about the library
• Light-weight (~400 LOC)– Polymorphic secure code for free!
• Practical– Simple (Monads)– Features: files, references, stdio/stdout, and more– Declassification
• Limitations– Timing leaks– Static security lattice
Future directions
• Networking
• Cryptography (declassification)
• The flexibility of Haskell together with providing information-flow as a library allows to include features with little effort!
• Others?
Some ideas (for master thesis?)
• Integrity policies in the code– Discretionary policies
• How untrusted code can use resources?
– Data invariants (indexes of arrays always fit into their boundaries)
– Non-interference integrity policies• Untrusted data cannot affect trusted data• Endorcement
• Can integrity policies be included in the library in a modular manner? – Topic worth to explore!!!
End