13
Extensible Security Architectures for Java Dan S. Wallach* Dirk Balfanz Drew Dean Edward W. Felten [email protected] [email protected] [email protected] [email protected] Department of Computer Science Princeton University Abstract Mobile code technologies such as Java, JavaScript, and ActiveX generally limit 911 programs to a single restrictive security policy. However, software-based protection can allow for more extensi- ble security models, with potentially significant performance im- provements over traditional hardware-based solutions. An extensi- ble security system should be able to protect subsystems and im- plement policies that are created after the initial system is shipped. We describe and analyze three implementation strategies for inter- posing such security policies in softwarebased security systems. Implementations exist for all three strategies: several vendors have adapted capabilities to Java, Netscape and Microsoft have exten- sions to Java’s stack introspection, and we built a name space man- agement system as an add-on to Microsoft Internet Explorer. The- oretically, all these systems are equivalently secure, but many pram- tical issues and implementation details favor some aspects of each system. 1 Introduction As the World Wide Web has been used to build increasingly com- plex applications, developers have been constrained by the Web’s static document model. “Active” content can add simple anima- tions to a page, but it can also transform the Web into a “platform” for writing and distributing programs. A variety of mobile code sys- tems such as Java [18], JavaScript [12], ActiveX [30], and Shock- wave [40] make this possible. Users and developers love mobile code, but it raises serious secu- rity concerns. Software distribution over theInternet has been com- mon for years, but the risks are greatly amplified with Web plug- ins and applets by virtue of their ubiquity and seamless integration. Users are often not even aware of mobile code’s presence. Mobile code systems must have correspondingly stronger security to com- pensate for the increased exposure to potentially hostile code. This paper considers the problem of securely supporting mobile code on real-world systems. Unlike traditional operating systems, Web browsers must rely on software mechanisms for basic mem- ory safety, both for portability and performance. Currently, there is no standard for constructing secure services above basic mem- ory safety primitives. We explain three different strategies and their implementations in Java: several vendors [14, lo] have built capa- bility systems, Netscape and Microsoft have extensions to Java’s stack introspection, and we designed an add-on to Microsoft Inter- net Explorer which hides or replaces Java classes. We analyze these systems in terms of established security criteria and conclude with *Portions of this work were done at Netscape Ccunmunications Corp. Permission to make digital/hard copy of pari or all this work for personal or classroom use is granted without fee provided that copies are not made or distributed for profit or commercial advan- tage, the copyright notice, the title of the publication and its date appear, and notice is given that copying is by permission of ACM, Inc. To copy otherwise, to republish, to post on servers, or to redistribute to lists, requires prior specific permission and/or a fee. SOSP-16 IO/97 Saint-Malo, France 0 1997 ACM 0-89791~916~5/97/0010...$3.50 a discussion of appropriate environments in which to deploy each strategy. 1.1 The Advantages of Software Protection Historically, memory protection and privilege levels have been im- plemented in hardware: memory protection via base I limit regis- ters, segments, or pages; and privilege levels via user/kernel mode bits or rings [41]. Recent mobile code systems, however, rely on software rather than hardware for protection. The switch to soft- ware mechanisms is being driven by two needs: portability and performance. Portability The first argument for software protection is portabll- ity. A user-level software product like a browser must coexist with a variety of operating systems. For a Web browser to use hardware protection, the operating system would have to provide access to tho page tables and system’calls, but such mechanisms are not availnblc universally across platforms. Software protection allows a browser to have platform-independent security mechanisms. Performance Second, software protection offers significantly cheaper cross-domain calls’. To estimate the magnitude of the per- formance difference, we did two simple experiments. The results below sho$d not be considered highly accurate, since they mix measurements from different architectures. However, the effect wo are measuring is so large that these small inaccuracies do not affect our conclusions. First, we measured the performance of a null call between Com- mon Object .Model (COM) objects on a 180 MHz PentiumPro PC running Windows NT 4.0. When the two objects are in different tasks;the call takes 230psec; when the called object is in a dynam- ically linked library in the same task, the call takes only 0,2 psec - a factor of 1000 difference. While COM is a very different sys- tem from Java, the performance disparity exhibited in COM would likely also appear if hardware protection were applied to Java. This ratio appears to be growing even larger in newer processors [36,1], The time difference would be acceptable if cross-domain calls were very rare. But modem software structures, especially in mo- bile code systems, are leading to tighter binding between domains. To illustrate this fact, we then instrumented the Sun Java Virtual Machine (JVM) (JDK 1.0.2 interpreter running on a 167 MHz Ul- trasparc) to measure the number of calls across trust boundaries, that is, the number of procedure calls in which the caller is either more trusted or less trusted than the callee. We measured two work- loads. CaffeineMark is a widely used Java performance bench- mark, and SunExamples is the sum over 29 of the 35 programs3 on Sun’s sample Java programs page4. (Some of Sun’s programs run ‘In Unix, a system-call crosses domains between user aad kernel pro- cesses. In Java, amethod oall between applet and system classes also crosses domains because system classes have additional privileges. ‘http://www.webfayre.com/pendragon/cm2/ 1 3We omitted internationalization examples and JDK 1.1 applets. 4h~tp://www.javasoft.com/applets/applets.html 116

Extensible Security Architectures for Javanieh/teaching/e6118_s00/... · Extensible Security Architectures for Java ... control to flow through security checks before executing any

  • Upload
    others

  • View
    19

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Extensible Security Architectures for Javanieh/teaching/e6118_s00/... · Extensible Security Architectures for Java ... control to flow through security checks before executing any

Extensible Security Architectures for Java

Dan S. Wallach* Dirk Balfanz Drew Dean Edward W. Felten [email protected] [email protected] [email protected] [email protected]

Department of Computer Science Princeton University

Abstract

Mobile code technologies such as Java, JavaScript, and ActiveX generally limit 911 programs to a single restrictive security policy. However, software-based protection can allow for more extensi- ble security models, with potentially significant performance im- provements over traditional hardware-based solutions. An extensi- ble security system should be able to protect subsystems and im- plement policies that are created after the initial system is shipped. We describe and analyze three implementation strategies for inter- posing such security policies in softwarebased security systems. Implementations exist for all three strategies: several vendors have adapted capabilities to Java, Netscape and Microsoft have exten- sions to Java’s stack introspection, and we built a name space man- agement system as an add-on to Microsoft Internet Explorer. The- oretically, all these systems are equivalently secure, but many pram- tical issues and implementation details favor some aspects of each system.

1 Introduction

As the World Wide Web has been used to build increasingly com- plex applications, developers have been constrained by the Web’s static document model. “Active” content can add simple anima- tions to a page, but it can also transform the Web into a “platform” for writing and distributing programs. A variety of mobile code sys- tems such as Java [18], JavaScript [12], ActiveX [30], and Shock- wave [40] make this possible.

Users and developers love mobile code, but it raises serious secu- rity concerns. Software distribution over theInternet has been com- mon for years, but the risks are greatly amplified with Web plug- ins and applets by virtue of their ubiquity and seamless integration. Users are often not even aware of mobile code’s presence. Mobile code systems must have correspondingly stronger security to com- pensate for the increased exposure to potentially hostile code.

This paper considers the problem of securely supporting mobile code on real-world systems. Unlike traditional operating systems, Web browsers must rely on software mechanisms for basic mem- ory safety, both for portability and performance. Currently, there is no standard for constructing secure services above basic mem- ory safety primitives. We explain three different strategies and their implementations in Java: several vendors [14, lo] have built capa- bility systems, Netscape and Microsoft have extensions to Java’s stack introspection, and we designed an add-on to Microsoft Inter- net Explorer which hides or replaces Java classes. We analyze these systems in terms of established security criteria and conclude with

*Portions of this work were done at Netscape Ccunmunications Corp.

Permission to make digital/hard copy of pari or all this work for personal or classroom use is granted without fee provided that copies are not made or distributed for profit or commercial advan- tage, the copyright notice, the title of the publication and its date appear, and notice is given that copying is by permission of ACM, Inc. To copy otherwise, to republish, to post on servers, or to redistribute to lists, requires prior specific permission and/or a fee. SOSP-16 IO/97 Saint-Malo, France 0 1997 ACM 0-89791~916~5/97/0010...$3.50

a discussion of appropriate environments in which to deploy each strategy.

1.1 The Advantages of Software Protection Historically, memory protection and privilege levels have been im- plemented in hardware: memory protection via base I limit regis- ters, segments, or pages; and privilege levels via user/kernel mode bits or rings [41]. Recent mobile code systems, however, rely on software rather than hardware for protection. The switch to soft- ware mechanisms is being driven by two needs: portability and performance.

Portability The first argument for software protection is portabll- ity. A user-level software product like a browser must coexist with a variety of operating systems. For a Web browser to use hardware protection, the operating system would have to provide access to tho page tables and system’calls, but such mechanisms are not availnblc universally across platforms. Software protection allows a browser to have platform-independent security mechanisms.

Performance Second, software protection offers significantly cheaper cross-domain calls’. To estimate the magnitude of the per- formance difference, we did two simple experiments. The results below sho$d not be considered highly accurate, since they mix measurements from different architectures. However, the effect wo are measuring is so large that these small inaccuracies do not affect our conclusions.

First, we measured the performance of a null call between Com- mon Object .Model (COM) objects on a 180 MHz PentiumPro PC running Windows NT 4.0. When the two objects are in different tasks;the call takes 230psec; when the called object is in a dynam- ically linked library in the same task, the call takes only 0,2 psec - a factor of 1000 difference. While COM is a very different sys- tem from Java, the performance disparity exhibited in COM would likely also appear if hardware protection were applied to Java. This ratio appears to be growing even larger in newer processors [36,1],

The time difference would be acceptable if cross-domain calls were very rare. But modem software structures, especially in mo- bile code systems, are leading to tighter binding between domains.

To illustrate this fact, we then instrumented the Sun Java Virtual Machine (JVM) (JDK 1.0.2 interpreter running on a 167 MHz Ul- trasparc) to measure the number of calls across trust boundaries, that is, the number of procedure calls in which the caller is either more trusted or less trusted than the callee. We measured two work- loads. CaffeineMark is a widely used Java performance bench- mark, and SunExamples is the sum over 29 of the 35 programs3 on Sun’s sample Java programs page4. (Some of Sun’s programs run

‘In Unix, a system-call crosses domains between user aad kernel pro- cesses. In Java, amethod oall between applet and system classes also crosses domains because system classes have additional privileges.

‘http://www.webfayre.com/pendragon/cm2/ 1 3We omitted internationalization examples and JDK 1.1 applets.

4h~tp://www.javasoft.com/applets/applets.html

116

Page 2: Extensible Security Architectures for Javanieh/teaching/e6118_s00/... · Extensible Security Architectures for Java ... control to flow through security checks before executing any

Workload time crossings crossingshec

CaffeineMark 40.9 1135975 26235 SunExamples 138.7 5483828 35637

Figure 1: Number of trust-boundary crossings for two Java work- loads. Time is the total user+system CPU time used, in seconds. Crossings is the number of method calls which cross a trust bound- ary, The last column is their ratio: the number of boundary cross- ings per CPU-second.

forever; we cut these off after 30 seconds.) Note that our measure- ments almost certainly underestimate the rate of boundary crossings that would be seen on a more current JVM implementation that used a just-in-time (JlT) compiler to execute much more quickly.

Figure 1 shows the results. Both workloads show roughly 30000 boundary crossings per CPU-second. Using our measured cost of 0.2 psec for a local COM call, we estimate that these programs spend roughly 0.5% of their time crossing trust boundaries in the Java system with software protection (although the actual cost in Java may be significantly cheaper).

Using our measured cost of 230 pet for a cross-task COM call, we can estimate the cost of boundary crossings for both workloads in a hypothetical Java implementation that used hardware protec- tion. The cost is enormous: for CaffeineMark, about 6 seconds per useful CPU-second of work, and for SunExamples, about 8 seconds per useful CPU-second. In other words, a ndive implementation of hardware protection would slow these programs down by a factor of 7 to 9. This is unacceptable.

Why are there so many boundary crossings? Surely the designers did not strive to increase the number of crossings; most likely they simply ignored the issue, knowing that the cost of crossing a Java protection boundary was no more than a normal function call. What our experiments show, then, is that the natural structure of a mobile code system leads to very frequent boundary crossings.

Of course, systems using hardware protection are structured dif- ferently; the developers do what is necessary to improve perfor- mance (i.e., buffering calls together). In other words, they deviate from the natural structure in order to artificially reduce the number of boundary crossings. At best, this neutralizes the performance penalty of hardware protection at a cost in both development time and the usefulness and maintainability of the resulting system. At worst, the natural structure is sacrificed and a significant perfor- mance gap still exists.

1.2 Memory Protection vs. Secure Services Most discussions of software protection in the OS community fo- cus on memory protection: guaranteeing a program will not access memory or execute code for which it is not authorized. Software fault isolation [46], proof-carrying code [33], and type-safe lan- guages are three popular ways to ensure memory protection.

1.2.1 Software Memory Protection Lucco, et al., introduced sofnvarefad# isolation [46] in 1993. They showed they could rewrite load, store, and branch instructions to validate all memory access with an aggregate 5-30% slowdown. By eliminating these checks where possible, and optimizing the place- ment of the remaining checks, a perhaps acceptable slowdown is achieved in a software-only implementation. The theory is still the same as hardware-based protection: potentially dangerous opera- tions are dynamically checked for safety before their execution.

Necula and Lee introduced proof-carrying code [33] in 1996. Proof-carrying code eliminates the slowdown associated with soft- ware fault isolation by statically verifying a proof that a program re- spects an agreed upon security policy when the program is loaded.

After the proof is verified, the program can run at full speed. Few limits are put on the form of the program; it can be hand-tuned as- sembly language. The major difficulty at the moment is generating the proofs: for now, they are written by hand with the help of anon- interactive theorem prover. Research is underway to automate proof generation. One promising idea is to have the compiler for a safe language generate a proof of memory safety during the compilation process.

The language-based protection model, exemplified by Java, can be traced back at least to the Burroughs B-5000 in 1961 1271 and is also used in current research operating systems such as SPIN [3]. Memory accesses can be controlled with a safe language [31]. If the language has a mechanism for enforcing abstraction boundaries (in Java, this means ensuring that private variables and meth- ods are not accessible outside their class), then the system can force control to flow through security checks before executing any dan- gerous code. Language-based safety can use either dynamic type checking [38, 61 or static type checking (as is mostly the case in Java [IS, 91). The major tradeoff is performance versus theoreti- cal complexity. The static system should be faster, because it only checks safety once, before the program starts. Dynamic checking is simpler, because there is no need to prove a type soundness the- orem: at each step during execution, a local check is sufficient to ensure the absence of type errors. Note that while static type check- ing may be theoretically complex, the implementation can be quite simple. 1.2.2 Secure Services While memory protection is necessary and important, there is much more to security than memory protection. Memory protection is sufficient for programs that do calculations without invoking sys- tem services, but more interesting programs use a rich set of oper- ating system services such as shared files, graphics, authentication, and networking. The operating system code implementing these services must define and correctly enforce its own security policy pertaining to the resources it is managing. For example, the GUI code must define and enforce a policy saying which code can ob- serve and generate which GUI events. Memory protection can keep hostile code from directly reading the GUI state, but it cannot keep a hostile program from tricking the GUI code into telling it about events it shouldn’t sees.

Seltzer, et al. [42], studied some of the security problems in- volved in creating an extensible operating system. They argue that memory protection is only part of the solution; the bulk of their pa- per is concerned with questions of how to provide secure services. Consider the security flaws that have been found in Unix. Very few are related to hardware memory protection: almost all of the flaws have been in trusted services such as sendmail and f ingera. Perfect memory protection would not prevent these flaws.

The challenge, then, is not only getting memory protection but providing secure system services. This paper considers how secure services can be built solely with software protection.

2 Security in Java Though we could in principle use any of several mobile code tech- nologies, we will base our analysis on the properties of Java. Java is a good choice for several reasons: it is widely used and analyzed in real systems, and full source code is available to study and modify.

Java uses programming language mechanisms to enforce mem- ory safety. The JVM enforces the Java language’s type safety, pre- venting programs from accessing memory or calling methods with- out authorization [28]. Existing JVM implementations also enforce

5GUI event manipulation may seem harm&. but observing GUI events could allow an attacker to see passwords or other sensitive information while they are typed. Generated GUI events would allow aa attacker to create keystrokes to execute dangerous commands.

117

Page 3: Extensible Security Architectures for Javanieh/teaching/e6118_s00/... · Extensible Security Architectures for Java ... control to flow through security checks before executing any

a simple “sandbox” security model which prohibits untrusted code from using any sensitive system services.

The sandbox model is easy to understand, but it prevents many kinds of useful programs from being written. All file system access is forbidden, and network access is only allowed to the host where the applet originated. While untrusted applets are,successfully pre- vented from stealing or destroying users’ files or snooping around their networks, it is also impossible to write a replacement for the users’ local word processor or other common tools which rely on more general networking and file system access.

Traditional security in Java has focused on two separate, fixed se-. curity policies. Local code, loaded from specific directories on the same machine as the JVM, is completely trusted. Remote code, loaded across a network connection from an arbitrary source, is completely untrusted.

Since local code and remote code can co-exist ‘in the same JVM, and can in fact call each other, the system needs a way to determine if a sensitive call, such as a network or file system access, is exe- cuting “locally” or “remotely.” Traditional JVMs have two inherent properties used to make these checks:

l Every class’in the JVM which came from the network was loaded by a ClassLoader, and includes a reference to its Class- Loader. Classes which came from the local file system have a special system ClassLoader. Thus, local classes can be distin- guished from remote classes by their ClassLoader.

l Every frame on the call stack includes a reference to the class running in that frame. Many language features, such as the default exception handler, use these stack frame annotations for debugging and diagnostics. ’

Combined together, these two JVM implementation properties al- low the security system to search for remote code on the call stack. If a ClassLoader other than the special system ClassLoader exists on the call stack, then a policy for untrusted remote code is applied. Otherwise, a policy for trusted local code is used.

To enforce these policies, all the potentially dangerous methods in the system were designed to call a centralized SecurityManager class which checks if the action requested is allowed (using the mechanism described above), and throws an exception if remote code is found on the call stack The SecurityManager is meant to implement a reference monitor [25,32] -always invoked, tamper- proof, and easily verifiable for correctness.

III practice, this design proved insufficient. First, when an appli- cation written in Java (e.g., the HotJava Web browser) wishes to run applets within itself, the low-level file system and networking code has a problem distinguishing between direct calls from an applet and system functions being safely run on behalf of an applet. Sun’s JDK 1.0 and JDK 1.1 included specific hacks to support this with hard-coded “ClassLoader depths” (measuring the number of stack frames between the low-level system code and the applet code).

In addition to a number of security-related bugs in the first im- plementations [8], many developers complained that the sandbox policy, applied equally to all apple& was too inflexible to imple- ment many desirable “real” applications. The systems presented here can all distinguish between different “sources” of programs and provide appropriate policies for each of them.

3 Approaches We now present three different strategies for resolving the inflex- ibility of the Java sandbox model. All three strategies assume the presence of digital signatures to identify what principal is respon- sible for the program. This principal is mapped to a security policy. After that, we have identified three different ways to enforce the policy:

Capabilities A number of traditional operating systems were based on unforgeable pointers which could be safely given to user code. Java provides a perfect environment for implement- ing capabilities.

Extended stack introspection The current Java method of in- specting the stack for unprivileged code can be extended to include principals on the call stack.

Name space management An interesting property of dynamic loading is the ability to create an environment where different applets see different classes with the same names. By restrlct- ing an applet’s name space, we can limit its activities.

&I this section, we will focus on how each method implements in- terposition of protective code between potentially dangerous prim- itives and untrusted code. In section 4, we will compare these sysq tems against a number of security-relevant criteria.

3.1 Common Underpinnings Security mechanisms can be defined by how they implement inter- posirion: the ability to protect a component by routing all calls to it through a reference monitor. The reference monitor either rejects each call, or passes it through to the protected component; the refcr- en& monitor can use whatever policy it likes to make the decision, Since a wide variety of policies may be desirable, it would be nice if the reference monitor were structured to be extensible without bc- ingrewritten. As new subsystems need to be protected, they should be easy to add to the reference monitof.

Traditionally, extensible reference monitors are built using trusted subsystems. For example, the Unix password tile is read- only, and only a setuid program can edit it. In a system with do- main and type enforcement [2], the password database would have a type that is only editable by programs in the appropriate domain, In either case, the operating system has no CI priori knowledge of the password database or password-changing utilities, but instead has security mechanisms general enough to protect the data by only allowing a small number of programs access to it. Clark and Wil- son [7] offer a particularly cogent argument in favor of the use of trusted subsystems and abstraction boundaries in the security of commercial systems. 3.1.1 Digital Signatures as Principals To implement any security policy, Java needs a notion of principal. III a traditional operating system, every user is a principa16. For Java, we wish to perform access control based on the “source” of the code, rather than who is running it. This is solved by digitally signing the applet code. These signatures represent endorsettrerlts of the code by the principal who signed it’ asserting that the code is not malicious and behaves as advertised. When a signature is verified, the principal may be attached to the class object withln the JVM. Any code may later query a class for its principal, This allows a group of classes meant to cooperate together to query each others’ principal and verify that nothing was corrupted.

There is no reason a program cannot have multiple signatures, and hence multiple principals. This means we must be able to com- bine potentially conflicting permissions granted to each principal, much as a traditional operating system must resolve permissions when a user belongs to multiple groups. One way to solve this problem is to choose a dominating principal, generally the prlnci- pal about whom the user has the strongest feelings, and treat the program as though it were signed only by the dominating principal, Some systems also define an algebra for combining policies.

6Principul and target, as used in this paper, arc the same as srrbfect arid object, as used in the security lltemture, but are more clear for discussing security in object-oriented systems.

‘Because a signature can be stripped or replaced by a third-party, there is no strong way for a signatunz to guarantee authorship.

118

Page 4: Extensible Security Architectures for Javanieh/teaching/e6118_s00/... · Extensible Security Architectures for Java ... control to flow through security checks before executing any

3.1.2 Policies and Users

Each system needs a policy engine which can store security pol- icy decisions on stable storage, answer questions about the current policy, and query the user when an immediate decision is neces- sary, The details of what is stored, and what form user queries take, depend on the specific abstractions defined by each system.

To clarify the policy engine’s role, consider the file system pro- tection mechanisms in Unix: The “policy decisions” in a Unix file system are the file permission bits for each directory and file; these are stored on disk. The role of policy engine is played by code in the kernel that maintahrs the permission bits and uses them to decide which file access requests to allow.

In Java, a critical issue with the policy engine is how to help non- technical users make security-relevant decisions about who they trust to access particular resources. To simplify the user inter- face, we want to pre-define groups of common privileges and given them user-friendly names. For example, a “typical game privileges” group might refer to specific limited file system access, full-screen graphics, and network access to the game server. Such groupings allow a single dialog box to be presented to a user which does not burden the user with a long series of individual privilege decisions and their corresponding dialog boxes.

3.1.3 Site Administration

Another way to remove complexity from users is to move the work to their system administrators. Many organizations prefer to cen- trally administrate their security policy to prevent users from acci- dentally or maliciously violating the policy.

These organizations need hooks into the Web browser’s pol- icy mechanism to either pre-install and “lock down” all security choices or at least to pre-approve applications used by the organi- zation. If an organization purchases a new product, all users should not be burdened with dialogs asking them to grant it privileges. Likewise, if a Web site is known to be malicious, an administra- tor could block it from ever asking any user for a privilege.

Both Netscape and Microsoft have extensive support for central- ized policy administration in their Web browsers. While malicious users may not necessarily be prevented from reinstalling their Web browser (or operating system) to override the centralized security policies, normal users can at least benefit from their site administra- tors’ work to pre-determine which applications should and should not be trusted.

3.2 First Approach: Capabilities In many respects, Java provides an ideal environment to build a traditional capability system [ll, 271. Electric Communities [lo] and JavaSoft [14]* have implemented such systems. This section discusses general issues for capabilities in Java, rather than specifics of the Electric Communities or JavaSoft systems.

Dating back to the 1960% hardware and software-based capa- bility systems have often been seen as a good way to structure a secure operating system [19,34,44]. Fundamentally, a cupubiZity is an unforgeable pointer to a controlled system resource. To use a capability, a program must have been first explicitly given that ca- pability, either as part of its initialization or as the result of calling another capability. Once a capability has been given to a program, the program may then use the capability as much as it wishes and (in some systems) may even pass the capability to other programs. This leads to a basic property of capabilities: any program which lms a capability must have been permitted to use its.

8The Jaw Electronic Commerce Framework (JECF) uses a eapabiity- style interface, extending the signed applet support in JDK 1.1. More information about JavaSoft’s security architeetom plans can be found in Gong [16].

gFor example, the combination to open a safe represents a capability.

3.2.1 capabmtles rn Java

In early machines, capabilities were stored in tagged memory. A user program could load, store, and execute capabilities, but only the kernel could create a capability [27l. In Java, a capability is simply a reference to an object. Java’s type safety prevents object references from being forged. It likewise blocks access to methods or member variables which are not labeled public.

The current Java class libraries already use a capability-style in- terface to represent open files and network connections. However, static method calls are used to acquire these capabilities. In a more strongly capability-based system, all system resources (including the ability to open a file in the first place) would be represented by capabilities. In such a system, an applet’s top-level class would be passed an array of capabilities when initialized. In a tlexible security model, the system would evaluate its security policy be- fore starting the applet, then pass it the capabilities for whatever resources it was allowed. If an applet is to be denied all file system access, for example, it need only not receive a file system capabil- ity. Alternately, a centralized “broker” could give capabilities upon request, as a function of the caller’s identity.

3.2.2 Interposition

Java capabilities would implement interposition by providing the exclusive interface to system resources. Rather than using the File class, orthepublic constructorofFileInputStream,aprogram would be required to use a file system capability which it acquired on startup or through a capability broker. If a program did not re- ceive such a capability, it would have no other way to open a file.

Since a capability is just a reference to a Java object, the ob- ject can implement its own security policy by checking arguments before passing them to its private, internal methods. In fact, one capability could contain a reference to another capability inside it- self. As long as both objects implement the same Java interface, the capabilities could be indistinguishable from one another.

For example, imagine we wish to provide access to a subset of the file system - only files below a given subdirectory. One possi- ble implementation is presented in figure 2. A SubFS represents a capability to access a subtree of the file system. Hidden inside each SubFS is a FileSystem capability; the SubFS prepends a fixed string to all pathnames before accessing the hidden FileSys tern Any code which already possesses a handle to a FileSys tern can create a SubFS, which can then be passed to au untrusted sub- system. Note that a SubFS can also wrap another SubFS, since SubFS implements the same interface as FS.

Also note that with the current Java class libraries, a program wishing to open a tile can directly construct its own FileInputStream. To prevent this, either FileInputStream must have non-public constructors, or the FileInputStrearn class must be hidden from programs. This restriction would also apply to other file-related Java classes, such as RandomAccessFile. While the Java language can support capabilities in a straightforward manner, the Java runtime libraries (and all code depending on them) would require significant changes.

3.3 Second Approach: Extended Stack Introspection

This section presents an extension to Java’s current stack- introspection mechauismlO. This approach is taken by both

The safe has no way to verify if the combination has been stolen; any person entering the correct combination can open the door. The seeority of the safe depends upon the combination not being leaked by an authorized holder.

loThis approach is sometimes ineont~tly referred to as “capability-based secnri~ in some marketing literature.

119

Page 5: Extensible Security Architectures for Javanieh/teaching/e6118_s00/... · Extensible Security Architectures for Java ... control to flow through security checks before executing any

// In this example, any code wishing to open // a file must first obtain an object which // implements FileSystem.

interface FileSystem { public FileInputStream getInputStream(String path);

I

// This is the primitive class for accessing // the file system. Note that the constructor // is not public -- this restricts creation // of these objects to other code in the // same package.

public class FS implements FileSystem { FSO 0

public FileInputStream getInputStream(String path) {

return internalOpen(path); 1

private native FileInputStream internalOpen(path);

I

// This class allows anyone holding // FileSystem to export a subset of

a

// file system. Calls to getInputStream0 // are prepended with the desired file system // root, then passed on to the internal // FileSystem capability.

public class SubFS implements FileSystem { private FileSystem fs; . private String rootpath;

public SubFS(String rootPath, FileSystem fs) {

this.rootPath = rootPath; this.fs = fs;

1

public FileInputStream getInputStream(String path) (

// to work safely, this would need // to properly handle I..' in path return fs.getInputStream(rootPath +

n/u + path);

I 1

Figure 2: Interposition of a restrict,ed file system root in a capability-based Java system. Both FS and SubFS implement FileSystem,theinterfaceexport& toallcodewhi~hreadsfiles.

Netscape” and Microsoft12 in version 4.0 of their respective browsers. JavaSoft is working on a similar design [17]. Although the designs of Netscape and Microsoft differ in many ways, there is a core of similarity. Accordingly, we will first describe the common elements and then discuss the differences.

As in the other approaches, extended stack introspection uses digital signatures to match pieces of incoming byte code to prln- cipals, and a policy engine is consulted to determine which code has permission for which targets.

33.1 Basic Design

Three fundamental primitives are necessary to use extended stack introspection:

l enableprivilege (target)

l disablePrivilege ( target)

l checkprivilege (target)

When a dangerous resource (such as the file system) needs to be protected, two steps are necessary: a target must be defined for the resource, and the system must call checkprivilege ( 1 on the targetbeforeaccessingtheprotectedresource.

When code wishes to we the protected resource, it must first call enablePrivilege on thetargetassociated withthatre- source. This will consult the policy engine to see whether the prln- cipal of the caller is permitted to use the resource. If permitted, it will create an enabled privilege. After accessing the resource, thecodewillcalldisablePrivilege 0 todiscardtheenabled privilege. checkprivilege (target) searches for an enabled prlvi*

lege to the given target. If one is not found, an exception is thrown.

3.3.2 Improved Design

The design as described so far is simple, but it requires a few refine- ments to make it practical. First, it is clear that enabled privileges must apply only to the thread that created them. Otherwise, an un- fortunately timed thread switch could leak privileges to untrusted code.

Second, the basic design is flawed in that an enabled privilege could live forever if the programmer neglected to disable it on all paths out of the method that created it. This error is easy to make, especially in the presence of exceptions, so the design is refined to attach enabled privileges to a hidden and protected field of the stack frame of the method that created them. This would cause s the privileges to be discarded automatically when the method that created them exits.

The design has one more serious weakness: it is subject to luring

attacks in which trusted code that has some privileges enabled Is tricked into calling into untrusted code. This would have the effect of delegating the enabled privileges to the untrusted code, which could exploit them to do damage. Calls from trusted to untrusted code are common, for example in callbacks associated with Java’s system library functions such as the Abstract Windowing Toolklt.

The solution to luring attacks is to use a more restricted stack- frame searching algorithm in checkprivilege ( 1. This algo- rithm, which both Netscape and Microsoft use, is shown in figure 3. The algorithm searches the frames on the caller’s stack in sequence, from newest to oldest. The search terminates, allowing access, upon finding a stackframethathas anappropriateenabled privilege. The search terminates, forbidding access (and throwing an exception),

l~http://developer.netscape.com/library/ documentation/signedobj/ '2http://www.microsoft.com/ie/ie4Q/browser/

security/sandbox.htm

120

Page 6: Extensible Security Architectures for Javanieh/teaching/e6118_s00/... · Extensible Security Architectures for Java ... control to flow through security checks before executing any

checkPrivilege(Target target) { // loop, newest to oldest stack frame

// this class shows how to implement a trusted

foreach stackFrame { // subsystem with stack introspection

if(stackFrame has enabled privilege for target) return Allow;

public class FS implements FileSystem { private boolean usePrivs = false;

if(policy engine forbids access to target by class executing in stackFrame) return Forbid;

1

// if we get here, we fell off the end // of the stack if (Netscape) return Forbid; if (Microsoft) return Allow;

I

Figure 3: The stack walking algorithm used by Netscape and Mi- crosoft.

upon finding a stack frame which is forbidden by the policy engine from accessing the target.

This neatly eliminates luring attacks: untrusted code cannot ex- ploit the privileges of its caller, because the stack search will ter- minate upon finding the untrusted stack frame. A callee can some- times use the privileges of its caller, but only those privileges that the callee could have requested for itself.

We note that Netscape and Microsoft take different actions when the search reaches the end of the stack uneventfully: Netscape de- nies permission and Microsoft allows it. The Netscape approach follows the principle of least privilege, since it requires that privi- leges be explicitly enabled before they can be used. The Microsoft approach, on the other hand, may be easier for developers, since no calls to enableprivilege ( ) are required in the common case where independent untrusted or semi-trusted applets are using more-trusted system libraries. It also allows local, trusted Java ap- plications to use the same JVhl without modification: they run as a trusted principal so all of their accesses are allowed by default13.

33.3 Example: Creating a Busted Subsystem

A trusted subsystem can be implemented as a class that enables some privileges before calling a system method to access the pro- tected resource. Untrusted code would be unable to directly access the protected resource, since it would be unable to create the nec- essary enabled privilege. Figure 4 demonstrates how code for a trusted subsystem may be written.

Several things are notable about this example. The classes in figure 4 do not need to be signed by the system principal (the all- powerful principal whose privileges are hard-wired into the JVM). They could be signed by any trusted principal. This allows third parties to gradually extend the security of the JVM without opening the entire system to attack.

With the trusted subsystem, an applet has two ways to open a file: call through TrustedService, which will restrict it to a subset of the file system, or request UniversalFileReadprivi- leges for itself. There are no other ways to enable privileges for the UniversalFileReadtarget,sotherearenootherwaystoopen a file, Note that, even should the applet try to create an instance of FS and then call getInputStream ( ) directly, the low-level file system call (inside java. io . FileInputStream) will still fail.

*3Netscape’s stack intmspection is currently only used in their Web browser, so compatibility with existing Java applications is not an issue.

public FS() {

try 1 PrivilegeManager.checkPrivilege(

“UniversalFileReadW); usePrivs = true;

} catch (ForbiddenTargetException e) { usePrivs = false;

1 1

public FileInputStream getInputStream(String path) {

// only enable privileges if they were // there when we were constructed

if(usePrivs) PrivilegeManager.enablePrivilege(

“UniversalFileRead”); return new

java.io.FileInputStream(path); I

I

// this class shows how a privilege is enabled // before a potentially dangerous operation

public class TrustedService { public static FileSystem getScratchSpace(){

PrivilegeManager.enablePrivilege( WniversalFileRead");

// SubFS class from the previous example return new SubFS("/tmp/TrustedServicen,

new FSO); I

I

Figure 4 ThisexampleshowshowtobuildaFileSystemcapa- biity (see figure 2) as an example of a protected subsystem using extended stack introspection. Note that figure 2’s SubFS can work munodifitxl with this example.

user UntrustedApplet()

SK&n SubFS.aetlnoutStream~~ < - . System F~,,getlnputStreamO--^‘“--‘l~]

Svsfem new FilelnputStfeam~

System SecuriiManager.checkFtead()

System PrivilegeManager.checkPrivilege()

Figure 5: This figure shows the call stack (growing downward) for a file system access by an applet using the code in fig- ure 4. The grey areas represent stack frames running with the UniversalFileReadptivilegeenabled. Notethatthetopsys- tern frames on the stack can run unprivileged, even though those classes have the system principal.

121

Page 7: Extensible Security Architectures for Javanieh/teaching/e6118_s00/... · Extensible Security Architectures for Java ... control to flow through security checks before executing any

3.3.4 Details The Netscape and Microsoft implementations have many additional features beyond those described above. We will attempt to describe a few of these enhancements and features here.

“Smart Targets” Sometimes a security decision depends not only on which resource (the file system, network, etc.) is being accessed, but on which specific part of the resource is involved, for example, on exactly which file is being accessed. Since there are too many files to create targets for each one, both Microsoft and Netscape have a form of “smart targets” which have internal param- eters and can be queried dynamically for access decisions. Details are beyond the scope of this paper.

Who can define targets? The Netscape and Microsoft systems both offer a set of predefined targets that represent resources that the JVM implementation wants to protect; they also offer ways to define new targets. The Microsoft system allows only fully trusted code to define new targets, while the Netscape system allows any- one to define new targets. In the Netscape system, targets are named with a (principal, string) pair, and the system requires that theprin- cipal field match the principal who signed the code that created the target. Built-in targets belong to the predefined principal System.

Allowing anyone to define new targets, as Netscape does, al- lows third-party library developers to define their own protected resources and use the system’s stack-introspection mechanisms to protect them. The drawback is that users may be asked questions regarding targets that the Netscape designers did not know about. This makes it harder to give the user guidance. Guidance from the principal that defined the target is probably safe to use, since the defining principal is the one whose security depends on proper use of the target. Still, it may be questionable to rely on third-party developers for part of the security user interface.

Signing Details Microsoft and Netscape also differ over their handling of digital signatures. In the Microsoft system, each bundle of code carries at most one signature14, and the signature contains a list of targets that the signer thinks the code should be given access to. Before the code is loaded, the browser asks the policy engine whether the signer is authorized to access the requested targets; if so, the code is loaded and given the requested permissions.

In the Netscape system, code may have several signers, and sig- natures mention no targets. Instead, once the code is loaded, the code itself must tell the policy engine which targets it will want access to. The decision whether to grant access to those targets is made by the policy engine, based on the identities of the sign- ers. Applets are strongly advised to request their privileges at startup, though this rule is not enforced. Failure to request privi- leges on startup might lead, for example, to the user working with a document-editing applet and then discovering that he cannot save his work without violating his security policy.

Since the Netscape system allows a class to be signed by several principals, there must be a way to combine the policy engine’s opin- ions about each of the signers into a single policy decision. This is done by using a “consensus voting” rule. Intuitively, consensus vot- ing means that one negative vote can force access to be forbidden, while at least one positive vote (and no negative votes) is required in order to allow access. Since the local user and site administrator may not know all of the signers, the policy engine can be told to vote “abstain” for an unknown signer.

Allowing multiple signers, as Netscape does, seems better than requiring a single singer. Since different users and sites may trust

“ActuaUy, a sequence of signatures is allowed, but the present imple- mentation recognizes only the first one.

different signers, multiple signatures are required in order to pro- duce a single signed object that everyone will accept. With a single- signature scheme, the server has to have multiple versions of the code (one for each signer) and must somehow figure out which ver- sion to send to which client. Also, one signer might sign a subset of the classes, creating a trusted subsystem within a potentially un- trusted applet.

Putting the target-access requests in the signature, as Microsoft does, provides superior flexibility in another dimension. It allows a signature to be a partial endorsement of a piece of code. For example, a site administrator might sign an outside applet, saying (in effect), ‘The local security policy allows this applet to access outside network addresses, but nothing more!’

Many other details of the Microsoft and Netscape designs arc omitted here for brevity.

3.4 Third Approach: Name Space Management This section presents a modification to Java’s dynamic linking mechanism which can be used to hide or replace the classes seen by an applet as it runs.

We have implemented a full system based on name space man- agement, as an extension to Microsoft Internet Explorer 3.0. Our implementation did not modify the JVh4 itself, but changed several classes in the Java library. The full system is implemented in 4500 lines of Java, most of which manages the user interface.

We first give an overview of what name space management 1s and how it can be used as a security mechanism. Then we describe our implement&on in detail.

3.4.1 Design

With name space management, we enforce a given security policy by controlling how names in a program are resolved into runtime classes. We can either remove a class entirely from the name space (thus causing attempts to use the class to fail), or we can cause its name to refer to a different class which is compatible with the original. This technique is used in Safe-Tel [6] to hide commands in an untrusted interpreter. Plan 9 [37] can similarly attach different programs and services to the file system viewed by an untrusted process.

In an object-oriented language, classes represent resources WC wish to control. For example, a File class may represent the file system and a Socket class may represent networking oper- ations. If the File class, and any other class which may refer to the file system, is not visible when the remote code is linked to local classes, then the file system will not be available to be attacked. In- stead, an attempt to reference the file system would be equivalent to a reference to a class which did not exist at all; an error or exception would be triggered.

To implement interesting security policies, we can create envi- ronments which replace sensitive classes with compatible ones that check their arguments and conditionally call the original classes. These new classes can see the original sensitive classes, but the mo- bile code cannot. For example, a File class could be replaced with one that prepended the name of a subdirectory (see figure 6), much

Original name Alice Bob java.net.Socket security.Socket java.net.Socket javaio.File - security.File

Figure 6: Different principals see different name spaces. In this example, code signed by Alice cannot see the File class, and for Bob it has been replaced with compatible subclasses.

122

Page 8: Extensible Security Architectures for Javanieh/teaching/e6118_s00/... · Extensible Security Architectures for Java ... control to flow through security checks before executing any

Figure 7: A Clusshder resolves every class in an applet. If these classes reference more classes, the same ClassLoader is used.

like the capability-based example in figure 2. In both cases, only a sub-tree of the file system is visible to the untrusted mobile code. In order for the program to continue working correctly, each sub- stituted class must be compatible with the original class it replaces (i.e., the replacement must be a subclass of the original).

To make name space management work as a flexible and general access control scheme, we introduce the notion of a conjiguration, which is a mapping from class names to implementations (i.e., Java class files). These configurations correspond to the privilege groups discussed in section 3.1.2. When mobile code is loaded, the policy engine determines which configuration is used for the code’s name space, as a function of its principal. If the principals have not yet been seen by the system, the user is consulted for the appropriate configuration.

An interesting property of this system is that all security deci- sions are made statically, before the mobile code begins execution. Once a class has been hidden or replaced, there is no way to get it back.

3.4.2 Implementation in Java Name space management in Java is accomplished through modi- fying the Java ClassLoader. A ClassLoader is used to provide the name + implementation mapping. Every class keeps a reference to a ClassLoader which is consulted for dynamic binding to other classes in the Java runtime. Whenever a new class is referenced, the ClassLoader provides the implementation of the new class (see figure 7).

Usually in a Web browser, an AppletChsLoader is created for each applet. The AppletClassLoader will normally first try to resolve a class name against the system classes (such as j ava. io . File) which ship with the browser. If that fails, it will look for other classes from the same network source as the applet. If two applets from separate network locations reference classes with the same name that are not system classes, each will see a different implementation because each applet’s AppletClassLoader looks to separate locations for class implementations.

Our implementation works similarly, except we replace each ap- plet’s AppletClassLoader with a PrincipalClassLoader which en- forces the configuration appropriate for the principals attached to that cIass (see figure 8). When resolving a class reference, a Princi- palClassLoader can

1. throw a ClassNotFoundExceptionif the calling princi- pal is not supposed to see the class at all (exactly the same behavior that the applet would see if the class had been re- moved from the class library - this is essentially a link-time error),

2. return the class in question if the calling principal has full ac- cess to it, or

3. return a subclass, as specified in the configuration for the ap- plet’s principal.

In the third case we hide the expected class by binding its name to a subclass of the original class. Figure 9 shows a class, security.File, which can replace java.io.File. When an applet calls new java. io .File ( q foo* 1, it will actually get an instance of security.File, which is compatible in ev- ery way with the original class, except it restricts file system ac- cess to a subdirectory. It might appear that this could be circum- vented by using Java’s super keyword. However, Java bytecode has no notion of super, which is resolved entirely at compile time. Note that, to achieve complete protection, other classes such as FileInputStream, RandomAccessFile, etc. need to be re- placed as well, as they also allow access to the file system.

Name space management also allows third-party trusted subsys- tems to be distributed as part of untrusted applets (see section 3.3.3). The classes of the trusted subsystem will have different principals from the rest of the applet. Thus, those classes may be allowed to see the “real” classes which are hidden from other applet classes.

The viability of name space management is unknown for fu- ture Java systems. New Java features such as the reflection API (a feature of JDK 1.1 which allows dynamic inquiry and invoca- tion of a class’s methods) could defeat name space management entirely. Also, classes which are shared among separate subsys- tems may be impossible to rename without breaking things (e.g., both file system and networking classes use Inputstream and Outputstream). Both reflection and the class libraries could be redesigned to work properly with name space management.

4 Analysis

Now that we have presented three systems, we need a set of criteria to evaluate them. This list is derived from Saltzer and Schroeder [39].

Economy of mechanism Designs which are smaller and simpler are easier to inspect and trust.

Fall-safe defaults By default, access should be denied unless it is explicitly granted.

Completemediation Every access to every object should be checked.

Least privilege Every program should operate with the minimum set of privi1ege.s necessary to do its job. This prevents acciden- tal mistakes becoming security problems.

Least common mechanism Anything which is shared among dif- ferent programs can be a path for communication and a poten- tial security hole, so as little data as possible should be shared.

Accountabiity The system should be able to accurately record “who” is responsible for using a particular privilege.

123

Page 9: Extensible Security Architectures for Javanieh/teaching/e6118_s00/... · Extensible Security Architectures for Java ... control to flow through security checks before executing any

HThlLpagewilhJava appler,

Figure 8: Changing the name space: A PrincipalClassLoader (PCL) replaces the original class loader. The class implementation returned depends on the principal associated with the PrincipalClassLoader and the configuration in effect for that principal.

p package securitv: i public

// // // // // // // // //

class Fiie extends java.io.File 1 Note that System.getUser() would not be available in a system purely based on name space management. In the current implementation, getUser examines the call stack for a PrincipalClassLoader. A cleaner implementation would want to generate classes on the fly with different hard-coded prefixes.

private String fixPath(String path) { // to work safely, this would need // to properly Fandle '..I in path

return "/tmp/m + System.getUser().getName() + W/" + path;

I

public File(String path) 1 super(fixPath(path));

I

public File(String path, String name) 1 super (fixPath(path1, name) ;

I I

Figure 9: Interposition in a system with name space management. We assume that at runtime we can find out who the currently run- ning principal is.

Psychological acceptability The system should not place an un- due burden on its users.

Several other practical issues arise when designing a security sys- tem for Java.

Performance We must consider how our designs constrain system performance. Security checks which must be performed at run-time will have performance costs.

Compatibility We must consider the number and depth of changes necessary to integrate the security system with the existing Java virtual machine and standard libraries. Some changes may be impractical.

‘,,

Remote calls If the security system can be extended cleanly to rc- mote method invocation, that would be a beneflt for building secure, distributed systems.

We will now consider each criterion in sequence.

4.1 Economy of Mechanism

Of all the systems presented, name space management is possibly the simplest. The i,mplementation requires redesigning the Class- Loader as well as tracking the different name space configurations. The mechanisms that remove and replace classes, and hence pro- vide for interposition, are minimal. Hbwever, they affect crltlcnl parts of the JVM and a bug in this code could open the system to attack.

Extended stack introspection requires some complex changes to the virtual machine. As before, changes to the JVM could desta- bilize the whole system. Each class to be protected must explicitly consult the security system to. see if it has been invoked by an au- thorized party. This check adds exactly one line of code, so its complexity is analogous to the configuration table in name space management. And, as with name space management, any security- relevant class which has not been modified to consult the security system can be an avenue for system compromise.

Unmodified capabilities are also quite simple, but they have well- known problems with confinement (see section 4.3). A capability system modified to control the propagation of capabilities would have a more complex implementation, possibly requiring stack in- trospection or name space management to work properly. A fully capability-based Java would additionally require redesigning the Java class libraries to present a capability-style interface - a sig- nificant departure from the current APIs, although capability-style classes (“factories”) are used internally in some Java APIs.

An interesting issue with all three systems is how well they en- able code ,auditing -how easy it is for an implementor to study the code and gain confidence in its correctness. Name space man- agementincludes anicelistofclasseswhich mustbeinspectcd for correctness. With both capabilities and stack introspection, simple text searching tools such as grep can locate where privileges arc acquired, and the propagation of these privileges must be carefully studied by hand. Capabilities can potentially propagate anywhcrc in the system. Stack annotations, however, are much more limited in their ability to propagate.

4.2 Fail-safe Defaults

Name space management and stack introspection have similar fail- safe behavior. If a potentially dangerous system resource has been properly modified to work with the system, it will default to deny

124

Page 10: Extensible Security Architectures for Javanieh/teaching/e6118_s00/... · Extensible Security Architectures for Java ... control to flow through security checks before executing any

access. With name space management, the protected resource can- not be named by a program, so it is not reachable. With stack in- trospection, requests to enable a privilege will fail by default. Like- wise, when no enabled privilege is found on the stack, access to the resource will be denied by default. (Microsoft sacrifices this property for compatibility ieasons.)

In a ti~lly capability-based system, a program cannot do anything unless an appropriate capability is available. In this respect, a capa- bility system has very good fail-safe behavior.

4.3 Complete Mediation Barring oversights or implementation errors (discussed in sec- tions 4.1 and 4.2), all three systems provide mechanisms to in- terpose security checks between identified targets and anyone who tries to use them.

However, an important issue is conjnement of privileges [26]. It should not generally be possible for one program to delegate a priv- ilege to another program (that right should also be mediated by the system). This is the fundamental flaw in an unmodified capability system; two programs which can communicate object references can share their capabilities without system mediation. This means that any code which is granted a capability must be trusted to care for it properly. In a mobile code system, the number of such trusted programs is unbounded. Thus, it may be impossible to ever trust a simple capability system. Likewise, mechanisms must be in place to revoke a capability after it is granted. Many extensions to ca- pabilities have been proposed to address these concerns. Kain and Landwehr [23] propose a taxonomy for extensions and survey many systems which implement them.

Fundamentally, extended capability systems must either place re- strictions on how capabilities can be used, or must place restric- tions on how capabilities can be shared. Some systems, such as ICAP [15], make capabilities aware of “who” called them; they can know who they belong to and become useless to anyone else. The IBM System/38 [4] associates optional access control lists with its capabilities, accomplishing the same purpose, Other systems use hardware mechanisms to block the sharing of capabilities [24]. For Java, any such technique would be problematic. To make a capa- bility aware of who is calling it, a certain level of introspection into the call stack must be available. To make a capability object un- shareable, you must either remove its class from the name space of potential attackers, or block all communication channels that could be used for an authorized program to leak it (either blocking all inter-program memory-sharing or creating a complex system of capability-sharing groups).

Name space management can potentially have good confine- ment properties. For example, if a program attempts to give an open FileInputStrem to another program which is for- bidden access to the file system, the receiving program will not be able to see the FileInputStream class. Unfortu- nately, it could still likely see InputStream (the superclass of FileInputStream), which has all thenecessary methods touse the object. If InputStream were also hidden, then networking code would break, as it also uses Inputstream. This problem could possibly be addressed by judicious redesign of the Java class libraries.

Stack introspection has excellent confinement. Because the stack annotations are not directly accessible by a program, they can nei- ther be passed to nor stolen by another program. The only way to propagate stack annotations is through method calls, and every sub- sequent method must also be granted sufficient privilege to use the stack annotation. The system’s access control matrix can thus be thought of as mediating delegation rights for privileges. Because the access matrix is consulted both at creation and at use of privi- leges, privileges are limited to code which is authorized to use them.

4.4 Least Privilege The principle of least privilege applies in remarkably different ways to each system we consider.

With name space management, privileges are established when the program is linked. If those privileges are too strong, there is no way to revoke them later - once a class name is resolved into an implementation, there is no way to unlink it.

In contrast, capabilities have very desirable properties. If a pro- gram wishes to discard a capability, it only needs to discard its ref- erence to the capability. Likewise, if a method only needs a subset of the program’s capabilities, the appropriate subset of capabilities may be passed as arguments to the method, and it will have no way of seeing any others. If a capability needs to be passed through the system and then back to the program through a call-back (a com- mon paradigm in GUI applications), the capability can be wrapped in another Java object with non-public access methods. Java’s package scoping mechanism provides the necessary semantics to prevent the intermediate code from using the capability.

Stack introspection provides an interesting middle-ground. A program which enables a privilege and calls a method is implicitly passing a capability to that method. If a privilege is not enabled, the corresponding target cannot be used. This allows straightforward auditing of system code to verify that privileges are enabled only for a limited time and used safely. If a call path does not cross a method that enables its privileges, then that call path cannot possibly use the privilege by accident. Also, there is a disableprivilege ( ) method which can explicitly remove a privilege before calling into untrusted code. Most importantly, when the method which enabled a privilege exits, the privilege disappears with it. This limits the lifetime of a privilege.

4.5 Least Common Mechanism The principle of least common mechanism concerns the dangers of sharing state among different programs. If one program can corrupt the shared state, it can then corrupt other programs which depend on it. This problem applies equally to all three Java-based systems. An example of this problem was Hopwood’s interface attack [8], which combined a bug in Java’s interface mechanism with a shared public variable to ultimately break the type system, and thus cir- cumvent system security.

This principle is also meant to discuss the notion of covert stor- age channeZs [26], an issue in the design of multi-level secure sys- tems [32]. Java presently makes no effort to limit or control covert channels, but this could be an interesting area for future work.

4.6 Accountability In the event that the user has granted trust to a program which then abuses that trust, logging mechanisms will be necessary to prove that damages occurred and then seek recourse.

In each system, the interposed protection code can always record what happened, but it requires more effort to identify the principal responsible.

In the stack introspection system, every call to enable a privilege can be logged, an administrator can learn which principal enabled the privileges to damage the system.

In a capability system, a capability can remember the principal to which it was granted and log this information when invoked. If the capability can be leaked to another program (see section 4.3), the principal logged will not be the same as the principal responsible for using the capability. A modified capability system would be necessary for strong accountability.

With name space management, information about principals is not generally available at run-time. This information could possibly be associated with Java threads or stored in static variables behind

125

Page 11: Extensible Security Architectures for Javanieh/teaching/e6118_s00/... · Extensible Security Architectures for Java ... control to flow through security checks before executing any

interposed classes. Likewise, capabilities could store a principal in a private variable.

This is all hypothetical, unfortunately, since current browsers do not provide the tamper-resistant logging necessary for trustworthy auditing. Once available, any of these architectures should be able to use it.

4.7 Psychological Akceptability The user interface is the most important aspect of the security sys- tem. If a Web browser shows its security dialog box too often, users will learn to ignore its contents and hit “OK” to continue what they were doing.

All three systems here can present the same fundamental inter- face to a user. When signed mobile code arrives in the Web browser, the user can be queried whether they trust the signatory. The-orig- inal version of Microsoft’s Authenticode [30] followed a “shrink- wrap” model - once the software was installed, it had unrestricted access to the user’s machine. The systems here can provide the user more fine-grained control over which privileges are granted. One promising strategy is for the Web browser to allow common “profiles” of privileges with intuitive-sounding names (e.g., “typical game privileges”) rather than a low-level list of primitives (limited file access, limited network access, full-screen video, etc.).

The user must become involved in security decisions at some point. The important question is ,when. There are two choices: ei- ther when the applet is loading or when the applet attempts a priv- ileged operation. Both times have advantages and disadvantages. The advantages of asking early are that the user does not spend time working in .an applet only to find out that they cannot save their work, and the applet cannot generate a series of fake security dialogs to get the user in the habit of clicking “OK”.15 The dis- advantage is that the user must decide what privileges to grant an applet before the applet starts running, so a user camrot try out an applet first. The advantage of asking the user later is that the applet has done as much as it can without privilege, so the user may quit the applet first, and never see a security dialog. The disadvantages are the vulnerability to the spoofing outlined above, and the fact that the user may be stuck with no way to save their last hour of work. It is not clear that either strategy is always correct.

All of the architectures discussed in this paper potentially allow for security dialogs to occur either early or late. The dialog can always be presented early, and the answer remembered for later. A capability system could use the late strategy by displaying the dialog only when a privileged capability is requested The stack introspection model naturally accommodates the late strategy, by presenting the dialog when checking whether a privilege is enabled, i.e., as a privileged operation is requested. For name space manage- ment, implementing the late strategy would be based on the lazy na- ture of dynamic linking in Java: a class does not have to be loaded until it is actually needed. Netscape’s implementation of stack in- trospection uses the late strategy, while Microsoft’s stack introspec- tion and our name space management use the early strategy.

In all cases, the user’s security preferences can be saved persis- tently, to prevent repeated dialog boxes. Additionally, these per- sistent privileges could be preset by the user’s site administrator, further reducing the need for dialog boxes.

4.8 Performance As discussed in section 1, performance is one of the attractions of language-based protection. Because hardware protection is so much slower than any of the systems presented in this paper, we will instead discuss the performance differences among the three

tsWbile the sandbox model puts up a warning strip on windows opened by untrusted code, windows opened by JavaScript have no such warning.

software systems. In all cases, we are assuming that the JVM uses a JIT compiler to generate and execute efficient machine code.

The stack introspection system has the highest runtime costs. At runtime, system classes must check whether the current enabled privileges allow them to proceed. At worst, this will have cost pro- portional to the current stack depth. These checks occur less often then one might think. Currently, stack introspection is used only to guard when a file or network connection is opened (an already exd pensive operation). The input and output streams act as capabilities for the open file or network connection and need no further security checks on read and write operations. While a specific input or out- put stream could leak, the general ability to open a file or network connection would still be contained.

Name space management does not incur any overhead at runtimc, nor do unmodified capability systems. However, all systems must pay similarruntime costs when they implement interposition layers (i.e., to validate or limit arguments to low-level system routines),

4.9 Compatibility One lesson we learned from the implementations of both nnmc space management and extended stack introspection is that lan- guage based protection can be implemented on top of a type-snfe language without diverging much from the original specification of that language. For both name space management and stack intro- spection, old apple& those written against the original Java API and unaware of the new security mechanisms, will continue to run un- modified in browsers equipped with the new authorization scheme, As long as they only use features allowed by the traditional sandbox security policy, they will notice no difference.

A notable exception are capability systems. As mentioned in section 4.1, a capability system would require a new library API and thus completely break compatibility with traditional Java APIs,

4.10 Remote Calls Recent systems are beginning to offer convenient distributed pro- gramming in Java, using a distributed object model similar to that of SRC network objects [5] or CORBA [43]. It would be highly desirable for language based security schemes to easily extend to a distributed environment. A single security policy and implcmen- tation mechanism could deal naturally with both local and remote code.

Capabilities extend quite naturally across a network. If remote object references include an unguessable string of bits (i.e., 128 random bits), then a remote capability reference has all the security properties of a local capability [44,15] (assuming all communlcn- tion is suitably encrypted to prevent eavesdropping). Unfortunately, the confinement issues discussed in section 4.3 become even more problematic. If the capability is leaked to a third party, then the third party has just as much power to use the capability as its in- tended holder. By themselves, networked capabilities offer no way for an object to identify its remote caller. However, if the remote method invocation used a cryptographically authenticated channel (as provided by SSL [I31 or Taos [47]), the channel’s remote idcn- tity might be useful. Gong [15] and van Doom, et al. [45] describe implementations of this.

Name space management is comparable to the directory services offered by most RPC systems. The directory server, which CM be reached through a well-known mechanism, is used to map names to objects. An interesting possrbility would be for a secure directory server to provide different objects to different remote identities.

Stack introspection is interesting because it helps answer the question “on whose behalf is this request running?“. This can be- come very complex to answer when RPCs pass through a num- ber of different systems,, calling one another. Secure RPC Stan- dards [20,35] refer to this as delegation. When Java code is rcceiv-

126

Page 12: Extensible Security Architectures for Javanieh/teaching/e6118_s00/... · Extensible Security Architectures for Java ... control to flow through security checks before executing any

ing a remote method call and invoking another one, the stack anno- tations could possibly help mediate the delegation information.

Actually building a secure RPC system using any of the mecha- nisms in Java is future work. Current Java RPC systems, with the possible exception of Electric Communities [lo], have no provi- sions for flexible security policies.

5 Conclusion

Software-based protection systems are coming into common use, driven by their inherent advantages in both performance and porta- bility. Software fault isolation, proof-carrying code, or language- based mechanisms can be used to guarantee memory-safety. Secure system services cannot be built without these mechanisms, but may require additional system support to work properly.

We have described three designs which support interposition of security checks between untrusted code and important system re- sources. Each design has been implemented in Java and both ex- tended stack introspection and name space management have been integrated in commercial Web browsers.

All three designs have their strengths and weaknesses. For ex- ample, capability systems are implemented very naturally in Java. However, they are only suitable for applications where programs are not expecting to use the standard Java APIs, because capabili- ties require a stylistic departure in API design.

Name space management offers good compatibility with existing Java applets but Java’s libraries and newer Java mechanisms such as the reflection API may limit its use.

Extended stack introspection also offers good compatibility with existing Java applets and has reasonable security properties, but its complexity is troubling and it relies on several artifacts of Sun’s Java Virtual Machine implementation.

We believe the best solution is to combine elements of these tech- niques. Name space management allows transparent interposition of security layers between system and applet code with no run-time performance penalty. Stack introspection can allow legacy system code to run with less than full privileges without being rewritten in a capability style, Yet, capabilities provide a well understood exten- sion to remote procedure calls. Understanding how to create such a hybrid system is a main area for future research.

6 Acknowledgments

Thanks to Jim Roskind, Raman Tenneti, and Tom Dell of Netscape for helping us understand their design, and to Netscape for sup- porting Dan Wallach as a visiting member of the design and im- plementation group. Thanks to Jeff Bisset, Mike Jerger, and Mike Toutonghi for helping us understand the Microsoft design. Any re- maining errors in the description of these designs are ours.

We also thank Li Gong for helping us solidify our ideas. Thanks to Andrew Appel, Mark Miller, Marianne Mueller, Ben Renaud, and Frank Yellin for many interesting conversations about our work Martfn Abadi, Dan Boneh, Luca Cardelli, Simson Gartlnkel, Rob Shillner, and Steve Wallach gave valuable feedback on drafts of this paper. Dave Gifford and the anonymous referees made many helpful suggestions.

Our work is supported by donations from Sun Microsystems, Bellcore, and Microsoft. Edward Felten is supported in part by an NSF National Young Investigator award.

References

14

PI

131

141

r51

PI

171

Bl

PI

WI

1111

WI

1131

1141

WI

ANDERSON, T. E., LEVY, H. M., BERSHAD, B. N., AND LAZOWSKA, E. D. The interaction of architecture and oper- ating system design. In Proceedings of the Fourth ACM Sym- posium on Architectural Support for Programming Languages and Operating Systems (1991).

BADGER, L., STERNE, D. F., SHERMAN, D. L., WALKER, K. M., AND HAGHIGHAT, S. A. Practical domain and type enforcement for UNIX. In Proceedings of the 1995 IEEE Symposium on Security and Privacy (1995), pp. 66-77.

BERSHAD, B. N., SAVAGE, S., PARDYAK, P., SIRER,E. G., FIUCZYNSKI, M., BECKER, D., EGGERS, S., AND CHAM- BERS, C. Extensibility, safety, and performance in the SPIN operating system. In Proceedings of 15th ACMSymposium on Operating Systems Principles (Dec. 1995), pp. 251-266.

BERSTIS, V., TRUXAL, C. D., AND RANWEILER, J. G. Sys- tem/38 addressing and authorization. In ZBMSystem/38 Tech- nical Developments, 2nd ed. IBM, July 1980, pp. 51-54.

BIRRELL, A., NELSON, G., OWICKI, S., AND WOBBER, E. Network objects. In Proceedings of 13th ACM Symposium on Operating Systems Principles (Dec. 1993), pp. 217-230.

BORENSTEIN, N. S. Email with a mind of its own: The Safe- Tel language for enabled mail. In IFZP International Working Conference on Upper Layer Protocols, Architectures and Ap- plications (1994).

CLARK, D., AND WILSON, D. A comparison of commercial and military computer security policies. In Proceedings of the 1987 IEEE Symposium on Security and Privacy (Oakland, CA, May 1987).

DEAN, D., FELTEN, E. W., AND WALLACH, D. S. Java security: From HotJava to Netscape and beyond. In Proceed- ings of the 1996 IEEE Symposium on Security and Privacy (Oakland, CA, May 1996), pp. 190-200.

DROSSOPOULOU, S., AND EISENBACH, S. Java is type safe - probably. In Proceedings of the Eleventh European Con- ference on Object-Oriented Programming (June 1997).

ELECTRIC COMMUNITIES. The Electric Communi- ties Trust Manager and Its Use to Secure Java, Sept. 1996. http://www.communities.com/company/ papers/trust/.

FABRY, R. S. Capability-based addressing. Communications of the ACM 17,7 (July 1974), 403-411.

FLANAGAN, D. JavaScript: The Dejinitive Guide, 2nd ed. O’Reilly &Associates, Inc., Jan. 1997.

FREIER, A. O., KARLTON, P., AND KOCHER, P. C. The SSL Protocol: Version 3.0, Mar. 1996. Internet draft, f tp : I / ietf.cnri.reston.va.us/internet-drafts/ draft-freier-ssl-version3-Ol.txt.

GOLDSTEIN, T. The Gateway Security Model in the Java Electronic Commerce Framework. JavaSoft, Nov. 1996. http://www. javasoft.com/products/ commerce/jecf-gateway.ps.

GONG, L. A secure identity-based capability system. In Pro- ceedings of the 1989 IEEE Symposium on Security and Pri- vacy (Oakland, CA, May 1989), pp. 56-63.

127

Page 13: Extensible Security Architectures for Javanieh/teaching/e6118_s00/... · Extensible Security Architectures for Java ... control to flow through security checks before executing any

WI

r.171

E31

WI

WI

WI

WI

v31

WI

WI

WI

WI

[=I

P91

[301

II311

1321

I331

[341

GONG, L. New security architectural directions for Java. In Proceedings of IEEE COMPCON ‘97 (Feb. 1997).

GONG, L. personal communication, 1997.

GOSLING, J., JOY, B., AND STEELE, G. The Java Language Specijcation. Addison-Wesley, 1996.

HARDY, N. KeyKOS architecture. ACM Operating Systems Review 19,4 (Oct. 1985), 8-25.

Hu, W. DCE Security Programming. O’Reilly &Associates, Inc., July 1995.

JAEGER, T., RUBIN, A. D.,.AND PRAKASH, A. Building systems that flexibly control downloaded executable content. In Sixth USENIXSecurity Symposium Proceedings (San Jose, CA, July 1996), pp. 131-148.

JONES, A. K., AND LISKOV, B. H. A language extension for controlling access to shared data. IEEE Transactions on Sojiware Engineering SE-2,4 (Dec. 1976), 277-285.

KAIN, R. Y., AND LANDWEHR, C. E. On access checking in capability-based systems. IEEE Transactions on Soflware Engineering SE-I3,2 (Feb. 1987), 202207.

KARGER, P. A., AND HERBERT, A. J. An augmented capa- bility architecture to support lattice security and traceability of access. In Proceedings of the 1984 IEEE Symposium on Security and Privacy (Oakland, CA, May 1984), pp. 2-12.

LAMPSON, B. W. Protection. In Proceedings of the Ftsh Princeton Symposium on Information Sciences and Systems (Princeton University, Mar. 1971), pp. 437-443. Reprinted in Operating Systems Review, 8(1):18-24, Jan. 1974.

LAMPSON, B. W. A note on the confinement problem. Com- munications of the ACM I6,lO (Oct. 1973), 613-615.

LEVY, H. M. Capability-Based Computer Systems. Digital Press, 1984.

LINDHOLM, T., AND YELLIN, F. The Java Krtual Machine Specification. Addison-Wesley, 1996.

MCGRAW, G., AND FELTEN, E. W. Java Security: Hostile Applets, Holes, and Antidotes. John Wiley end Sons, 1996.

MICROSOFT CORPORATION. Proposal for Au- thenticating Code Ku the Internet, Apr. 1996. http://www.microsoft.com/security/tech/ authcode/authcode-f.htm

MILNER, R., AND TOFTE, M. Commentary on Stanaizrd ML. MIT Press, Cambridge, MA, 1991.

NATIONAL COMPUTER SECURITY CENTER. Department of Defense TncFted Computer System Evaluation Criteria (The Orange Book). 1985.

NECULA, G. C., AND LEE, P. Safe kernel extensions without run-time checking. In Proceedings of the Second Symposium on Operating Systems Design and Implementation (OSDI ‘96) (Seattle, WA, Oct. 1996), pp. 229-243.

NEUMANN, P. G., BOYER, R. S., FEIERTAG,R. J., LEVITT, K. N., AND ROBINSON, L. A provably secure operating sys- tem: The system, its applications, and proofs. Tech. Rep. CSGll6,2nd Ed., SRI International, May 1980.

I351

1361

OBJECT MANAGEMENT GROUP. Common Secure Interoper- ability, July 1996. OMG Document Number: orbos/96-06-20.

OUSTERHOUT, J. K. Why aren’t operating systems getting faster as fast as hardware? In Ptvceedings of Summer 1990 VSENIX Conference (June 1990). pp. 247-256.

[371 PIKE, R., PRESOTTO, D., THOMPSON, K., AND TRICKBY, H. Plan 9 from Bell Labs. In Proceedings of the Summer 1990 UKUUG Conference (London, July 1990), pp. 1-9,

[381 REES, J. A. A security kernel based on the lambda-cnlculus, Tech. Rep. A.I. Memo No. 1564, Massachusetts Institute of Technology, Artificial Intelligence Laboratory, Mar. 1996.

WI

II401

[411

[421

SALTZER, J. H., AND SCHROEDER, M. D. The protection of information in computer systems. Proceedings of the IEEE 63,9 (Sept. 1975), 1278-1308.

SCHMITT, B. Shockwave Studio: Designing Multimedia for the Web. O’Reilly &Associates, Inc., Mar. 1997.

SCHROEDER, M. D., AND SALTZER, J. H. A hardware nr- chitecture for implementing protection rings. Commfmica- tionsoftheACMI5,3 @far, 1972), 157-170.

SELTZER,M. I., ENDO, Y., SMALL, C., AND SMITH, K. A. Dealing with disaster: Surviving misbehaved kernel exten- sions. In Proceedings of the Second Symposium on Operating Systems Design and Implementation (OSDI ‘96) (Oct. 1996), pp. 212227.

I431 SIEGEL, J., Ed. CORBA Fundamentals and Programming. John Wiley and Sons, 1996.

[44] TANENBAUM, A. S., MULLENDER, S. J., AND VAN RE- NESSE, R. Using sparse capabilities in a distributed opcratlng system. In 6th International Conference on Distributed Com- puting Systems (Cambridge, MA, May 1986), pp. 558-563.

[451 VAN DOORN, L., ABADI, M., BURROWS, M., AND Won- BER, E. Secure network objects. In Proceedings of the 1996 IEEESymposium on Security andprivacy (Oakland, CA, May 1996).

[46] WAHBE, R., Lucco, S., ANDERSON, T. E., AND GRAHAM, S. Efficient software-based fault isolation. In Proceedings of the Fourteenth Symposium on Operating System Principles (1993).

[47] WOBBER, E., ABADI, M., BURROWS, M., AND LAMPSON, B. Authentication in the Taos operating system. ACM Trans- actions on Computer Systems 12,1 (Feb. 1994), 332.

.

128