Many of the features of Java as a language (as introduced in Chapter 1) have important security implications. This is important for everyone: for developers charged with creating secure code; for users who must in the end rely on developers' products; for system administrators who install, configure, and manage the products; and for managers who decide which products are developed and how they are deployed. It is a well-known fact in computer security that security problems are very often a direct result of software bugs. That leads security researchers, including the authors, to pay lots of attention to software engineering. The hope is to avoid the ever-present penetrate-and-patch approach to security by developing more secure code in the first place. Although Java is no silver bullet, it can certainly help.
Object-orientation and a modern memory model both turn out to have a positive impact on Java security. The notions of data hiding, abstraction, and encapsulation, in particular, can help encourage better design for security. In Java, objects cannot be directly manipulated by a programmer; instead, they can only be accessed through their public interfaces. This is a good thing. Programmers cannot directly access memory either, but must use object references. This fact makes it much harder for a nasty program to trawl through memory looking for interesting data such as passwords and credit card numbers.
All of these features also help to make Java programs a bit more robust (on average) than programs written in other popular languages. After all, mechanisms that prevent programs from deliberately accessing memory that should be off-limits will also prevent buggy programs from accidentally accessing the wrong memory. Since most security flaws exist because of programming bugs, anything that reduces the general level of bugginess in software is good for security. Java helps conscientious programmers reduce the odds that their code contains security bugs.
Every object and primitive data element in Java has a built-in access level associated with it, either the explicit private, protected, or public access level, or a default access level.
There is an essential difference between languages like C++ and Java that stems directly from Java's requirement that objects can only be manipulated through standard interfaces. In C++, a programmer could declare certain variables inside an object private, but then access these variables in sneaky ways. Though the C++ compiler may stop obvious front-door operations (for example, not allowing an arbitrary class to access private elements of another), the back door is wide open. Using pointer arithmetic, casting, and other such means, a C++ programmer can scan through a program's allocated memory (and in fact, manipulate memory) at will. Why anyone would deliberately do such a thing inside his or her own code is an interesting question (although it might be done accidentally), but this sort of thing matters in Java where distinct applets that don't trust each other may share the same VM. The access levels described here help address this concern. Also helping to safeguard memory in Java are the following:
In this section, we have covered a nice set of features of Java that can help make it easier to write secure code (and help you rest easier if you use such code). However, how are these rules enforced? That is up to the Java sandbox.
Copyright ©1999 Gary McGraw and Edward Felten.