Design Principles for Secure Systems
CS 513 -- System Security -- January 29, 1998 -- Lecture 4
Lecturer: Professor Fred B. Schneider
Lecture notes by
Lynette I. Millett
We started the semester by arguing the need for trustworthiness in
networked information systems. Security is an element of
trustworthiness. We talked about the political and economic
considerations that affect the development and adoption of security
mechanisms. We considered security concerns in the physical world and
in daily life. These provide a basis (locks, value, police) upon which
to build security in cyberspace. We refer to this as the gold (Au)
standard: authentication, authorization, and
audit. Last time, we went over a real-life attack on the
Internet. Our analysis of the Internet worm suggests that today's
security attacks are not likely to be particularly subtle or deep, but
rather will exploit dull, known vulnerabilities.
Today, we will examine general architectural issues concerning the
building of secure systems and providing assurance of said
security. We do this now, rather than at the end of the course, in the
hope that these principles can drive discussion of specific security
issues that are brought up later on. Much of today's lecture is based
on the paper referenced in Further Reading.
Design principles for secure systems are as follows:
- Economy of Mechanism. Use small and simple mechanisms
wherever possible. This produces fewer errors in implementation
and makes possible
a more rigorous analysis of the implementation. Analysis can be
useful in providing
assurance. With respect to security, it is best to have no more
functionality than
necessary. Bells and whistles
add complication, and that introduces errors. Keep in mind
that security mechanisms implement policy. Our job is to come up
with mechanisms flexible enough to support the various policies
society might require.
- Failsafe Defaults. Access decisions should be based on the
explicit presence
of permissions rather than the absence of explicit exclusion.
In analyzing a large system,
some access avenues or possible behaviors may be overlooked; thus
the safest default is to
assume guilt (lack of access) until innocence is proven (explicit
authorization is specified). Designing systems in this spirit ensures
that unintended access will not occur.
- Complete Mediation. Every access to every object should be
checked.
Not only should every access be checked, for example,
on opening a file, but also on each subsequent read or write to that
file. (It is tempting, and easier implementation-wise, not to do all
this checking.) With complete mediation, security becomes system-wide,
encompassing initialization,
recovery and shutdown. Complete mediation also enables revocation
of access,
which is often needed to implement security policies. The possible
disadvantage of complete mediation is that
authentication is required. The security of the system will be only
as good as its
authentication mechanisms.
- Open Design. The principle of open design is controversial.
The idea
is that the security of a mechanism should not depend on ignorance by its
attackers. In other words: no security by obscurity. It should be
possible to publish source code for security mechanisms without
compromising their security. This
allows users of the system to increase their assurance in the
system. On the other hand, opening up source code for review can be
a security risk. Someone could find a vulnerability, not inform the
designers, and attempt to exploit it or sell the information later. NSA,
for instance, refused to publish their analysis that the DES encryption
algorithm is secure. They argued that publicizing such information
could make it easier to break the cryptosystem. The lack of information,
however, decreases people's assurance in the security of DES.
- Separation of Privilege. Two keys are better than one. Each
privilege should require a separate secret. The implication being:
separate passwords for separate objects. This allows fine-grained
control of access to the system, and limits what can be compromised if a
single secret is revealed.
- Least Privilege. Every program and every user should operate
using the least set of privileges necessary to complete the job. This
limits the damage that can result from an accident or error, and it limits
the number of privileged programs (which could be attacked) in the
system. It also helps in debugging, is good for increasing
assurance, and allows isolation of small critical subsystems.
- Least Common Mechanism. Every shared mechanism represents a
potential information path between users. Also, if shared, then these
mechanisms must be certified to the satisfaction for all users.
- Psychological Acceptability. This is a good principle, but has
not enjoyed
much success in practice. The issue is whether security mechanisms
can be made to feel intuitive to users. Consider programs like
spreadsheets and the desktop user interface. Both are relatively
simple for even novice computer users to understood and use. Security,
on the other hand, has not been presented in a way that is
intuitive. There do not seem to exist suitable metaphors
for conveying security principles.
This will stand in the way of widespread system security.
- Value vs. Mechanism. The cost of circumventing the mechanism should
be justified by the value of the resources being protected.
- Compromise Recording. We have been referring to this as "audit."
Systems should be built to audit themselves. Attackers are discouraged
by the very knowledge that their actions are being recorded.
It is true that there are tensions among the above principles. System
designers make tradeoffs based on knowledge of context, etc.
Two System Architectures
We turn to the question of how to engineer a system to be secure. There
are two system architectures we will discuss here.
A protected subsystem is a collection of programs and
data. Only programs in the collection can be used to access the
data. Also, access to programs is limited to allowing execution
starting from specified entry points. This structure presumes that the
subsystem has a way of running authentication routines, or does
authentication itself. In short, a programmable form of access control
to objects is created. The result is flexible, but changing the access
control policy requires changing the program, and thus this is not a
clear separation of policy and mechanism. The search for mechanisms
to create protected subsystems drove security research in operating
systems in the late 1970s.
The second architecture of interest is a security kernel.
We have already argued that to provide assurance that a system is
secure, all security mechanisms should be small and localized.
Security should be a fundamental abstraction built into the lowest
level of the system. The resulting abstraction, a reference
monitor, mediates all access to all objects. To implement a
reference monitor, a security kernel must be at the lowest level of
the system so that all accesses will be mediated.
There are several
principles for implementing a security kernel:
- Completeness: All accesses to all objects must be mediated by the
security kernel.
- Isolation: The security kernel must be protected from outside
tampering.
- Verifiability: To increase assurance, a correspondence must be
shown between the security policy and the actual implementation of
the security mechanisms in the security kernel.
Completeness and isolation are usually done with some kind of
hardware support (e.g. supervisor vs. user modes in a system).
Verifiability is accomplished through a mathematical proof.
The success of the security kernel depends on mechanisms
for completeness and isolation. In the case of the protected subsystem,
success depends on authentication and access to data. In both cases we
have identified a trusted security base (TCB). This
is the thing that must work for security to work. Throughout the
course we will be trying to uncover the TCB in our systems.