Sponsored Link •
This article turns to one aspect of Java's security model: the security manager of the Java virtual machine (JVM). The security manager, working in concert with the Java API, enables programmers to establish a custom security policy for their Java applications.
This month's article continues the discussion of Java's security model that began in August's "Under the Hood." In that article, I sketched overview of the security mechanisms built into the Java virtual machine (JVM). I also looked closely at one aspect of those security mechanisms: the JVM's built-in safety features. In September's column I examined the class loader architecture, and in the October column, the class verifier. In this installment of the security series, I describe the security manager -- the fourth and final piece of the JVM's core security architecture -- and I finish up with a brief discussion of the ways in which Java's security strategy extends beyond the JVM's architecture.
The security manager and the Java API
As described in last month's "Under the Hood," you can prevent code loaded by different class loaders from interfering with one another inside the JVM by using a class-file verifier. But to protect assets external to the Java virtual machine, you must use a security manager. The security manager defines the outer boundaries of the sandbox. (For a refresher on the Java sandbox, see the first section of my August "Under the Hood" column.)
A security manager is any class that descends from class
java.lang.SecurityManager. Because they are written in
Java, security managers are customizable. A security manager allows you
to establish a custom security policy for an application.
The Java API enforces the custom security policy by asking the security
manager for permission to take any action before it does something that
potentially is unsafe. For each potentially unsafe action, there is a
method in the security manager that defines whether or not that action
is allowed by the sandbox. Each method's name starts with "check," so,
checkRead() defines whether or not a thread
is allowed to read to a specified file, and
defines whether or not a thread is allowed to write to a specified
file. The implementation of these methods is what defines the custom
security policy of the application.
Most of the activities that are regulated by a "check" method are listed below. The classes of the Java API check with the security manager before they:
Because the Java API always checks with the security manager before it performs any of the activities listed above, the Java API will not perform any action forbidden under the security policy established by the security manager.
Areas unprotected by the security manager
Two actions not present in the above list that could potentially be unsafe are allocation of memory and invocation of threads. Currently, a hostile applet can crash a user's browser by:
These kinds of attacks are called denial of service attacks,
because they deny users the ability to use their own computers. The
security manager does not allow you to enforce any kind of limit on
allocated memory or thread creation. (There are no
methods in the security manager class.) The following are other kinds
of hostile applets that currently are possible:
So, a security manager isn't enough to prevent every possible action that could offend or inconvenience a user. Other than the attacks listed here, however, the security manager attempts to provide a check method that allows you to control access to any potentially unsafe action.
Installing a security manager
When a Java application starts, it has no security manager. At its option, the application can install one. If it does not install a security manager, no restrictions are placed on any activities requested of the Java API; the Java API will do whatever it is asked. (This is why Java applications, by default, do not have any security restrictions such as those that limit the activities of untrusted applets.) If the application does install a security manager, then that security manager will be in charge for the entire lifetime of that application. It can't be replaced, extended, or changed. From that point on, the Java API will fulfill only those requests that are sanctioned by the security manager.
In general, a "check" method of the security manager throws a security exception if the checked-upon activity is forbidden, and simply returns if the activity is permitted. Therefore, the procedure a Java API method generally follows when it is about to perform a potentially unsafe activity involves two steps. First, the Java API code checks whether a security manager has been installed. If not, it doesn't move to step two but goes ahead with the potentially unsafe action. If a security manager has been installed, the API code enacts step two, which is to call the appropriate "check" method in the security manager. If the action is forbidden, the "check" method will throw a security exception, which will cause the Java API method to abort immediately. The potentially unsafe action will never be taken. If, on the other hand, the action is permitted, the "check" method will simply return. In this case, the Java API method carries on and performs the potentially unsafe action.
Although you can install only one security manager, you can write the security manager so that it establishes multiple security policies. In addition to the "check" methods, the security manager also has methods that allow you to determine if a request is being made either directly or indirectly from a class loaded by a class loader object, and if so, by which class loader object. This enables you to implement a security policy that varies depending on which class loader loaded the classes making the request. You can also vary the security policy based on information about the class files loaded by the class loader, such as whether or not the class files were downloaded across a network or imported from the local disk. So even though an application can have only one security manager, that security manager can establish a flexible security policy that varies based on the trustworthiness of the code requesting the potentially unsafe action.
The support for authentication introduced in Java 1.1 in the
java.security package expands your ability to establish
multiple security policies by enabling you to implement a sandbox that
varies depending on who actually created the code. Authentication
allows you to verify that a set of class files was blessed as
trustworthy by some vendor, and that the class files were not altered
en route to your virtual machine. Thus, to the extent you trust the
vendor, you can ease the restrictions placed on the code by the
sandbox. You can establish different security policies for code that
comes from different vendors.
For links to more information about authentication and
java.security, see the Resources
at the bottom of this article.