[soen321-f04] week 7 material (Oct 14)[soen321-f04] week 7 material (Oct 14) David K. Probst PROBST at vax2.concordia.ca Thu Oct 14 14:20:01 EDT 2004 Previous message: [soen321-f04] week 6.2 material (Oct 14) Next message: [soen321-f04] material for week 6.1 (Oct 18) Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] SOEN 321 Week 7 Lecture Material _________________________________ last cryptographic item (before design-principles material) _______________________ The concept of perfect forward secrecy concerns a sequence of session keys, k1, k2, k3, ..., used to communicate secretly over time. Suppose that four keys have been generated and used so far (k1, k2, k3, k4) and that your system is suddenly compromised, leaking session key k4 and any material used to generate it. A system with *perfect forward secrecy* ensures that ciphertext encrypted with earlier session keys (k1, k2, k3) is still safe. Diffie-Hellman guarantees this. How? Now, consider Alice sending a sequence of session keys (a new one whenever it is required) to Bob. A --> B: {K1_AB}K+_B A --> B: {K2_AB}K+_B A --> B: {K3_AB}K+_B A bad guy records all these messages. Does this key-exchange protocol have perfect forward secrecy after a total break of Bob? Design Principles for Security-Conscious Systems ________________________________________________ There are eight principles. We start by naming them. 1. Principle of Least Privilege 2. Principle of Fail-Safe Defaults 3. Principle of Economy of Mechanism 4. Principle of Complete Mediation 5. Principle of Open Design 6. Principle of Separation of Privilege 7. Principle of Least Common Mechanism 8. Principle of Psychological Acceptability These are generally accepted design principles to guide the design and implementation of security mechanisms in support of security policies. In some sense, all of them are refinements of the top-level goals of _simplicity_ and _restriction_. Simplicity aids understanding. Restriction is about minimizing the power of an entity. 1) Least Privilege: Figure out the minimum set of capabilities a program requires to do its legitimate job, and grant exactly those. Make protection domains as small as possible. This is not always easy. Start by granting no capabilities and see where errors occur. This principle might eventually be combined with the idea of on-the-fly negotiation of access rights beteween re-negotiating processes and active objects. This is also the principle used to design security policy for sandboxes (or, for that matter, firewalls). Unix root is a strong negative example of this. Some programs need to run as root just to get one small privilege, such as binding to a low-numbered port. A buffer-overflow compromise of such a program while it is running as root will allow an attacker to gain complete control of the machine. Example: Tractorbeaming with wu-ftpd. This daemon tries to run with least privilege. Occasionally, it elevates its privilege with a bracketed pair of suid calls. But it does not disable signals. Hence, while it is in a "critical section", it can be tractorbeamed away to a signal handler that does not expect to be running with root privileges. Generating a signal is as easy as aborting a file transfer. If you win the critical race, you get unrestricted access to all resources. Moral: suid is not a robust mechanism for raising/dropping privilege because it does not guarantee the _atomicity_ of privilege. Least privilege is the whole motivation behind the use of sandboxes to confine partially-untrusted code. For example, Netscape plugins run in the browser's full address space, with no protection. Note that the assignment of privilege should be task-based rather than identity-based. Privileges should be relinquished promptly. And, in principle, access rights may be arbitrarily fine grained. Example: Unix root is a gross violation, both in terms of granularity and in terms of task-based versus identity-based rights granting. Processes should be confined to as small a protection domain as possible. This requires a new security model for OS design, possibly capability based with good revocation. Example: A mail server accepts mail from the Internet and enters messages onto the mail queue (spool directory). The server requires access to the network port and certain file permissions (create file, modify file). This allows the server to add headers to the mail message. After this is done, the server should drop all privileges to this file. 2) Fail-Safe Default: Start by denying all access, then allow only those accesses that have been explicitly permitted: - excess strictness will be caught as "false negatives", i.e., someone will complain - excess laxity, the certain result of "permit all, deny dangerous", leads to "false positives", i.e., permitting a dangerous service; you can be sure that attackers will not report these things to you Fail-safe defaults must be included in _shipped_ configurations. Often the shipped default is: trust everything! Also, restricting access to objects runs into the problem that objects rarely have canonical names. When you explicitly allow access using one particular name (of many), this is safe. Acess by other names is denied. And authorized users will have a path to the object. So, unless a subject is explicitly given permission to access an object, it should be denied access to that object. The default access to any object is _none_. Moreover, if the access cannot be completed successfully, then the subject should try to restore the original security state ("failure atomicity"). Example: Suppose the mail server above fails in creating a file in the spool directory. It should close the network connection, issue an error message, and stop. It should _not_ try to raise its privilege to get more powers to be able to take remedial action, e.g., write the file somewhere else. An attacker could piggyback such expanded privilege to gain access elsewhere; the conservative mail server does not allow the damage to spread. 3) Economy of Mechanism: Keep your implementation as simple as possible. Note that simple is different from small. Apply standard structured-programming techniques: clean interfaces between modules, avoidance of global state, etc. Interactions are a nightmare. You often need to check how each pair of subsystems will interact (sometimes it's even worse). For example, how many people would notice the interactions between the password checker and the page-fault mechanism? The complexity grows as Big-Omega(n^2) (or worse). Bellovin's Fundamental Theorem: Exposed machines should run as few programs as possible; the ones that do run should be as [simple] as possible. Example: the wizard-mode feature for remote debugging in sendmail was too tricky and hence was badly implemented. Example: The ftpd daemon allowed a client to run tar on the ftp server. But then people started using GNU tar, which allows the specification of arbitrary commands to run on the sever. All this is important for all subsystems, but it is especially important for the security mechanisms. As far as possible, push all the complexity out of the security code into the "normal" code. Every security mechanism should be as simple as possible. First, simplicity leads to better vulnerability detection. Second, simple systems are more frugal in the assumptions they make about the environment. Example: Suppose a local host uses ident to query a remote host, which has a TCP connection to the local host, for the username associated with the connecting process---as a basis for an access-control decision. This is mad; it assumes the connecting host is trustworthy. Example: Finger clients assume that finger servers are reasonable and, in particular, will provide a reasonable-sized response. The client will print all of it. What if it is _enormous_? In general, modules should be very careful about making assumptions about the well-formedness of input and output parameters that cross the interfaces to other modules. 4) Complete Mediation: Check every access to every object. In rare cases, you can optimize this securely by caching, but only if you are sure that nothing relevant in the environment will change. Note that this is not the distinction between ACLs and capabilities; the former require a new lookup, while the latter require the presentation of a valid (i.e., fresh) capability. Example: NFS does not perform complete mediation. In the NFS protocol, you contact mountd to get a filehandle, and then use the filehandle for all reads/writes on that file. Access to an exported directory is only checked by mountd at mount time. If you can guess or sniff the filehandle, you don't have to contact mountd at all; you can just access the file/directory directly with no controls. Each and every access should be checked to ensure that it is allowed. In particular, they should almost never be caching of rights that authorizes a sequence of accesses. Example: When an OS follows this rule, it receives a request and checks it. When it receives a second request from the same subject for the same type of access to the same object, it checks it again. Obviously, there are efficiency considerations. It is much easier to cache the first result and rely upon it for subsequent accesses. Example: Few OSs follow this rule. During a Unix file open, an active file descriptor is created and moved into the process' portion of kernel address space. This file descriptor is owned by the process until it closes the file. This obviously affects the granularity of revocation. 5) Open Design: The security of a mechanism should not depend on the secrecy of its design or implementation. Why is this wise? Those secrets may leak out by technical means, e.g., reverse engineering, or by nontechnical means, e.g., social engineering or other forms of information leakage. Open design is the alternative to (bad) security by obscurity. Security by obscurity is dangerous. Note: no one said, "Keep no secrets". Cryptographic protocols are published, but cryptographic keys are very closely guarded secrets. Open design is really about community-based vulnerability detection. Theorem: In contexts where community-based vulnerability detection ("debugging") is appropriate, take advantage of this great gift. There are two (general) arguments against security by obscurity: 1) Your design secrets will leak eventually (or your system will be compromised even if your secrets never leak!), and 2) Your system will actually benefit from having every one examine its strength. For security-critical code, you want as many people looking at it as possible. The bad guys are actually more efficient at doing this. Again, your system will actually _benefit_ from having every one examine its strength. But being open doesn't automatically make you secure. Firewall-1 was open source for many years before anyone actually bothered to take a look. The alternative to complacency is rigorous adversarial testing. For example, this is the _only_ way to separate the wheat from the chaff in cryptographic algorithms. Example: Many corporations have embarrassed themselves in the area of Digital Rights Management. The most recent brilliant mechanism to provide copy protection was defeated by pressing the shift key. The lawsuit against the individual who discovered this has been dropped. 6) Separation of Privilege: Require more than one check before granting access to an object. Say the probability of compromising one check is 1/2. Then the probability of compromising everyone of n checks is (1/2)^n. Often, you require more than one principal to "sign off" an an attempted access before granting it; there is fairly easy to do with cryptography. Example: On BSD-based Unices, su root has two preconditions. Not only must you know the root password, but you must be configured as a member of the _wheel_ group (gid of 0). A related idea is to support a trust model containing distributed and partial trust by implementing cyptosystem-based partial computatational abilities. Here, more than one principle is required to authorize (run) a computation. Imagine that two people have half a capability to run a program, and the capability expires when the program terminates (or aborts). 7) Least Common Mechanism: Mechanisms designed for one purpose should not be used for other purposes. Also, mechanisms used to access resources should not be shared. One needs to be careful with shared code: the assumptions originally made may no longer be valid. Example: Sometimes Java and Javascript and the browser talk to each other. Java and Javascript have different ways to get at the same information, and also different security policies. A malicious Java applet could cooperate with a malicious Javascript page to communicate information that neither could have communicated alone. Example: Microsoft common HTML-rendering code violates the principle of least common mechanism. HTML comes from both web servers and e-mail. The HTML-rendering code "knows" that Java and Javascript are unsafe when loaded from the Internet, but safe when loaded from local disk. But e-mail _is_ loaded from local disk! This principle is also related to the confinement problem and the problem of covert channels. Indeed, having common resource-access mechanisms creates denial-of-service vulnerabilities. 8) Psychological Acceptability: Security mechanisms should not make a system unreasonably more difficult to use. Whenever possible, security should be cognitively transparent in the sense of not imposing cognitive load on the user. Example: ssh has a directory for storing a public key locally that is not password protected. Ssh will connect, obtain the public key, and encipher the communication. The user needs to know nothing. Example: Suppose files are password protected. This is acceptable or not depending on the frequency of access. Examples: An onerous password policy will lead to a silent revolt ("Post-It Notes"). An onerous firewall policy will lead to installation of unauthorized modems. Interfaces to security mechanisms should be intuitively acceptable (e.g., NSA smart-card keying material in the shape of a brass key). You have to be able to sell your security model to your users. 9) [new principle] Orthogonal Security: Security mechanisms should be implemented othogonally to the systems they protect. Examples: wrappers (TCP wrappers, sandboxes, etc.) and intrusion-detection systems. (Think of one kind of intrusion-detection system as a network "burglar alarm"). --- Do cost/benefit analysis: a professional lock stops an amateur burglar, but merely delays a professional burglar of skill x by n time units. What strength threats do you choose to defend against? How high do you raise the cost of breaking into your system? These are non-trivial questions for corporations. Note: you can't really measure the time to crack your system when the vulnerabilities that will be used to break in are still unknown to you. Modern networked computer systems running complex applications are, in the last analysis, inscrutable. Be realistic: In most cases, you will need to layer compromise avoidance, compromise tolerance, and compromise detection, recording, and recovery. Compromise avoidance is nice; it's just theoretically impossible in the presence of sufficiently rich sharing. Compromise tolerance (e.g., sandboxing) is a very nice complementary technique. Detection and its friends are required because even layered compromise aviodance and tolerance doesn't work. Analogy: we try to debug our programs, but only fools think their programs are bug free. Military Security and the Orange Book _____________________________________ 1) Military security has three priorities: confidentiality is vital, high assurance is vital, and insider threats are vital. 2) The Orange Book is a specification for designing and certifying military-use trusted systems. Commercial developers were encouraged to build systems the military could trust. 3) "Trusted systems" were defined as "systems that employ sufficient hardware and software assurance measures to allow ... simultaneous processing of a range of sensitive or classified information". We want to put information of differing sensitivity levels on the same computer. Elaborate measures are specified with the highest levels of trusted systems, complete with requirements for rigorous mathematical proofs of the security properties---which are just the enforced security policies---of the systems. 4) The military model of security focuses on i) mandatory access controls; ii) security levels defined by ordered pairs, which are called "security labels"; and iii) rooting out covert channels---i.e., using abstract Trojan horses to sneak information across security perimeters. Covert channels can be arbitrarily bizarre. Consider a covert timing channel: the sender either busy waits or sleep waits, and the receiver measures CPU load. Or consider this "file" channel: A sender creates and deletes a protected file, and the reciver distinguishes between "File not found" and "Insufficient privilege for file access". Obviously, we need some synchronization here, possibly pre-arranged real time. 5) Orange book levels: D minimal. C1 Discretionary Security Protection (classic timesharing system, but few PCs). C2 Controlled Access Protection (access control at per-user granularity, clearing of allocated memory, auditing). B1 Labeled Security Protection (security labels, mandatory access controls). B2 Structured Protection (trusted paths, authentication mechanisms, notification of security-level changes, security kernel). B3 Security Domains (greater assurance, full mediation). A1 Verified Design (proof of implementation). 6) Orange book contributions: reference monitor (simple tamper-proof mechanism that implements access control with complete mediation), trusted computing base (TCB) (the smallest subset of the system that must be trusted if the system is to be secure), assurance (how do you _know_ the security properties of the TCB are X?), multilevel security, mandatory access controls, covert channels, object reuse limitations ("Sanitize object stores!"), heavy audit logs, and trusted paths (which can be very abstract). For example ask, what is the TCB of system X? 7) Mandatory access control: This is about insider attacks and Trojan horses. You can't access classified information unless both your security clearance is adequate and your compartments indicate a need to know. Mandatory but not discretionary access controls inhibit Trojan horses. Let C be the set of classification levels and W the set of codewords. A security label is an ordered pair , with l_c \in L and l_x \subset W. We define the partial order '<=' on the set of labels by: l <= l' iff l_c <= l'_c and l_w \subset l'_w The partially ordered set is in fact a lattice. Previous message: [soen321-f04] week 6.2 material (Oct 14) Next message: [soen321-f04] material for week 6.1 (Oct 18) Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] More information about the soen321-f04 mailing list