this lecture: server security what is the problem? you want to provide a public service on the Internet, e.g. sell thing now you are exposed to attacks from all over the world example: buffer overrun openssl is an implementation of SSL encryption (https://...) until 2002 it contained this code for parsing client requests: (simplified) id = malloc(32); read(msg); n = msg[0] memcpy(id, msg + 1, n); why is that a problem? is it exploitable? what could an attacker then do? problem just that C too low level? example: sql injection let's use just high-level languages (Python and SQL) q = "SELECT email FROM users WHERE name = " + name db.execute(q); what is the problem? problem just that programmers make errors? what are hackers trying to achieve? steal / modify your data. e.g. college admissions deface your web site for politics / revenge joy-riding acquire DDoS / spam bots problem: designers / programmers make errors is the only solution to eliminate each error? are there broad-brush solutions? I'm only going to talk about servers clients are much harder! software much more complex (UI) you have to fight against the user "you bank account is about to expire, click here to renew" non-technical approach: don't store data that would get you sent to jail don't store data whose disclosure would put you out of business verisign master private key credit card numbers, social security numbers transient only? outsource? but what if you need to store sensitive data? low-tech approach: totally separate systems accounting vs engineering separate nets, firewalls, virtual machines "isolation" but what if subsystems must interact? security for non-isolatable subsystems e.g. shopping basket web interface vs order DB e.g. blog viewer vs blog editor vs DB high-level plan: put each subsystem in a tight box define narrow interfaces, allow just exactly the needed function give subsystems *no* abilities beyond what they need two ideas: principle of least privilege (POLP) each subsystem can only see/modify data required for its job must be externally enforced you need to decompose system into subsystems! sensibly: e.g. blog editor shouldn't *need* access to passwords you need to have find-grained granting of privileges! privilege separation order subsystems by how exposed they are to attack give exposed subsystems fewer privs e.g. shopping basket can only insert into DB and order DB has no direct web interface how can we enforce POLP? each subsystem on a separate computer (or VM) narrow RPC interfaces, no other network ports expensive. even VMs are fairly heavy-weight. wouldn't want a VM per user POLP within a single host? maybe we want something micro-kernel like each subsystem in a separate process only interaction is IPC only let each subsystem send to approve IPC ports need fine-grain, so a port per file? worth thinking about but would be a lot of work big Mach-style UNIX server not useful here we want to be able to use stock operating systems POLP within a single UNIX host? (this is what the OKWS paper is about) the default w/ apache: almost all code runs in same process, as same user! once you break in, you can do almost anything to service's data run each subsystem in a separate process? separate UNIX user ID per subsystem (or user)? so can use UNIX privilege scheme X can't read Y's files X can't kill Y's processes would that work well? UNIX doesn't support POLP well often easy to escalate ordinary user to root my system has 49 setuid-root files, are they all secure? one is named ... how many system files whose mode must be just right? UNIX user IDs are a poor fit should my blog file have same UNIX owner as my profile file? not very secure if same awkward if different (e.g. if blog editor needs to update profile) you need to be root for some common actions change file ownership (i.e. when creating a user) creating network sockets so you're worried about bugs in s/w that runs as root there are 200 systems calls, all "on" by default could someone who broke into a sub-system do something bad? kill, ptrace, local socket to e.g. DB, inet socket as you to ??? what tools does UNIX provide that might be helpful for POLP? want to take away as much as possible by default and grant precisely what a subsystem should be able to do UNIX tool: chroot() system call changes what "/" refers to each struct proc has a separate root inode pointer to prevent most file-name operations: mkdir("d"); chdir("d"); chroot("d"); has a history of problems chdir("..") fd = open("."); chroot("subdir"); fchdir(fd); these have been fixed, but root can probably break out so: chdir("d"); chroot("d"); setuid(...); need to set up shared libraries, /etc/resolv.conf, &c and now of course it is hard to use file names! very limited what you can usefully put in chroot directory so need a different way to read/write data UNIX tool: file descriptor passing open the files a subsystem needs before fork()ing it it can read()/write() even if it can't open also e.g. sockets to DB server can send FDs dynamically sendmsg() can pass a file descriptor usefile for FDs needed after the fork() OKWS uses this to give sockets for client conns to subsystems FDs let us grant precise privileges i.e. just one file, just one socket like "capabilities" OKWS paper discussion figure 1 shows breakdown into subsystems==processes where is the bulk of the code? how do svc processes get at files? DB data? http sockets? analysis framework easy to break into a subsystem? subsystem has access to sensitive information/resources? easy/no and hard/yes maybe ok how well are exploits in one process isolated? buffer overrun in one svc files? ptrace? create socket to DB? erase log file? buffer overrun in okld? does okld run as root? catastrophic but unlikely: no client contact buffer overrun in okd? does okd run as root? how can it accept connections on port 80? can it read/write files e.g. log file? buffer overrun in pubd (e.g. file name too long)? can there be SQL injection bugs? what would it take to send arbitrary SQL to DB? buffer overrun in oklogd? how does okld create a service? get FDs from logger, pubd, okd fork(); chroot("/var/okws/run"); chdir("/coredumps/51001"); setgid(51001); setuid(51001); exec("service", fds...); why OK to run all services in same chroot directory? is process-per-service effective? in-memory state, use DB as another user why not process-per-user-per-service? OKWS conclusion pretty good at POLP pretty good at privilege separation required a lot of care and different programming style e.g. no files... what could o/s design do to make secure programming easier?