by Christopher Stone with Joe Weber
Before you write any applets or programs with Java, it is important to understand how Java works. This chapter introduces you to the actual language, the limitations of the language (intentional and unintentional), and how code can be made reusable.
Strictly speaking, Java is interpreted, although in reality Java is both interpreted and compiled. In fact, only about 20 percent of the Java code is interpreted by the browser--but this is a crucial 20 percent. Both Java's security and its ability to run on multiple platforms stem from the fact that the final steps of compilation are handled locally.
A programmer first compiles Java source into bytecode using the Java compiler. These bytecodes are binary and architecturally neutral (or platform-independent--both work equally well). However, the bytecode isn't complete until it's put together with a Java runtime environment--usually a browser. Because each Java runtime environment is for a specific platform, the bytecodes can be interpreted for the specific platform and the final product will work on that specific platform.
This platform-specific feature of Java is good news for developers. It means that Java code is Java code is Java code, no matter what platform you're developing for or on. You could write and compile a Java applet on your UNIX system and embed the applet into your Web page. Three different people on three different machines--each with different environments--can take a peek at your new applet. Provided that each of those people run a Java-capable browser, it wouldn't matter whether they are on an IBM, HP, or Macintosh. Using Java means that only one source of Java code needs to be maintained for the bytecode to run on a variety of platforms. One pass through a compiler for multiple platforms is good news for programmers.
The one drawback which comes with interpretation, however, is that there is a performance hit. This is caused by the fact that the browser has to do some work with the class files (interpret them) before they can be run. Under traditional programming (such as with C++) the code that is generated can be run directly by the computer. The performance hit that interpretation causes means that Java programs tend to run about 1/2 to 1/6th the speed of their native counterparts.
This deficiency is largely overcome using a tool called a Just-in-Time (JIT), compiler. A just-in-time compiler compiles Java methods to native code for the platform you're using. This compiler is embedded with the Java environment for a particular platform (such as Netscape). Without the JIT compiler, methods are not translated to native code, but remain in the original machine-independent bytecode. This bytecode is interpreted on any platform by the Java Virtual Machine. A Java application is portable, but the just-in-time compiler itself cannot be portable, because it generates native code specific to a platform, exactly as you need a different version of the virtual machine for each new platform. Generally you don't even need to concern yourself with JITs. Both the Netscape Navigator and Microsoft's Internet Explorer browsers have JIT compilers in them.
Why is this combination of compilation and interpretation a positive feature?
The fact that the final portion of compilation is being accomplished by a platform-specific device, which is maintained by the end user, relieves you of the responsibility of maintaining multiple sources for multiple platforms. Interpretation also allows data to be incorporated at runtime, which is the foundation of Java's dynamic behavior.
Java is an object-oriented language. Therefore, it's part of a family of languages that focuses on defining data as objects and the methods that may be applied to those objects. As I've explained, Java and C++ share many of the same underlying principles; they just differ in style and structure. Simply put, object-oriented programming languages (OOP, for short) describe interactions among data objects. To make an analogy using medicine, object-oriented doctors would be interested in holistic medicine--examining the body (or object) as a whole first and then determining the proper vaccines, diets, and medicine (the tools) to improve your health after that. Non object-oriented doctors would think primarily of their tools.
Many OOP languages support multiple inheritance, which can sometimes lead to confusion or unnecessary complications. Java doesn't. As part of its less-is-more philosophy, Java supports only single inheritance. That means each class can inherit from only one other class at any given time. This type of inheritance avoids the problem of a class inheriting classes whose behaviors are contradictory or mutually exclusive. Java allows you to create totally abstract classes known as interfaces. Interfaces allow you to define methods that you can share with several classes, without regard for how the other classes are handling the methods.
See Chapter 5, "Object-Oriented Programming," to learn more.
NOTE: Although Java does not support multiple inheritance, Java does allow a class to implement more than one interface.
See Chapter 11, "Classes," to learn more about classes and objects.
Objects can also implement any number of interfaces (or abstract classes). The Java interfaces are a lot like the Interface Definition Language (IDL) interfaces. This similarity means it's easy to build a compiler from IDL to Java.
That compiler could be used in the Common Object Request Broker Architecture, or CORBA, system of objects to build distributed object systems. Is this good? Yes. Both IDL interfaces and the CORBA system are used in a wide variety of computer systems, and this variety facilitates Java's platform independence.
See Chapter 37, "JavaIDL: A Java Interface to CORBA," to learn more about CORBA.
As part of the effort to keep Java simple, not everything in this object-oriented language is an object. Booleans, numbers, and other simple types are not objects, but Java does have wrapper objects for all simple types. Wrapper objects allow all simple types to be implemented as though they are classes. It is important to remember that Java is unforgivingly object-oriented; it simply does not allow you to declare anything that is not encapsulated in an object. Even though C++ is considered an OOP language, it allows you to develop bad habits and not encapsulate types.
See Chapter 7, "Data Types and Other Tokens," to learn more about types
Object-oriented design is also the mechanism that allows modules to "plug and play." The object-oriented facilities of Java are essentially those of C++, with extensions from Objective C for more dynamic method resolution.
The heart of Java is the Java Virtual Machine, or JVM. The JVM is a virtual computer that resides in memory only. The JVM allows Java programs to be executed on a variety of platforms as opposed to only the one platform for which the code was compiled. The fact that Java programs are compiled for the JVM is what makes the language so unique. But in order for Java programs to run on a particular platform, the JVM must be implemented for that platform.
See Chapter 48, "Inside the Java Virtual Machine," to learn more about the JVM.
The JVM is the very reason that Java is portable. It provides a layer of abstraction between the compiled Java program and the underlying hardware platform and operating system.
The JVM is actually very small when implemented in RAM. It was purposely designed to be small so that it could be used in a variety of consumer electronics. In fact, the whole Java language was originally developed with household electronics in mind. Gadgets such as phones, PCs, appliances, television sets, and so on will soon have the JVM in their firmware and allow Java programs to run. Cool, huh?
Java source code is compiled to the bytecode level, as opposed to the bitcode level. The JVM executes the Java bytecode. The javac program, which is the Java compiler, reads files with the .java extension, converts the source code in the .java file into bytecodes, and saves the resulting bytecodes in a file with a .class extension.
The JVM reads the stream of bytecode from the .class file as a sequence of instructions. Each instruction consists of a one-byte opcode, which is a specific and recognizable command, and zero or more operands (the data needed to complete the opcode). The opcode tells the JVM what to do. If the JVM needs more than just the opcode to perform an action, then an operand immediately follows the opcode.
See Chapter 47, "Understanding the .class File," to learn about opcodes.
There are four parts to the JVM:
The size of an address in the JVM is 32 bits. Therefore, it can address up to 4G of memory, with each memory location contaipØng one byte. Each register in the JVM stores one 32-bit address. The stack, the garbage-collection heap, and the method area reside somewhere within the 4G of addressable memory. This 4G of addressable memory limit isn't really a limitation now, as most PCs don't have more than 32M of RAM. Java methods are limited to 32K in size for each single method.
All processors use registers. The JVM uses the following to manage the system stack:
The Java development team decided that Java would only use four registers because if Java had more registers than the processor it was being ported to, then that processor would take a serious reduction in performance.
The stack is where parameters are stored in the JVM. The JVM is passed the bytecode from the Java program and creates a stack frame for each method. Each frame holds three kinds of information:
The heap is the collection of memory from which class instances are allocated. Any time you allocate memory with the new operator, that memory comes from the heap. You can call the garbage collector directly, but it is not necessary or recommended under most circumstances. The runtime environment keeps track of the references to each object on the heap and automatically frees the memory occupied by objects that are no longer referenced. Garbage collections run as a thread in the background and clean up during CPU inactivity.
The JVM has two other memory areas:
There is no limitation as to where these memory areas must actually exist, making the JVM more portable and secure. The fact that memory areas can exist anywhere makes the JVM more secure in the fact that a hacker couldn't forge a memory pointer.
The JVM handles the following primitive data types:
This section is organized into six parts. You will explore the issue of security of networked computing in general and define the security problem associated with executable content. I propose a six-step approach to constructing a viable and flexible security mechanism. How the architecture of the Java language implements security mechanisms will also becovered. As with any new technology, there are several open questions related to Java security, which are still being debated on the Net and in other forums.
In this section, you will analyze the concept of security in the general context of interactivity on the Web and security implementation via executable content.
First examine the duality of security versus interactivity on the Web and examine
the evolution of the Web as a medium in the context of this duality. Next, you will
arrive at a definition of the security problem in the context of executable content.
The Security Problem Defined
See Chapter 36, "Java Security in Depth," to
learn more about Java Security.
Does the user have to restrict completely the outside program from accessing any resource whatsoever on the computer? Of course not. This would cripple the ability of executable content to do anything useful at all. A more complete and viable security solution strategy would be a six-step approach:
Working backwards from the previous solution strategy, the security problem associated with executable content can be stated as consisting of the following six subproblems:
As you learn, Java has been designed from the ground up to address most (but probably
not all) of the security problems as defined here. Before you move on to Java security
architecture itself, I identify next the attack targets and scenarios. Table 2.1 lists the resources that could be potentially targeted and the type
of attack they could be subject to. A good security strategy will assign security/risk
weights to each resource and design an appropriate access policy for external executable
content. This following discussion is in reference to the six-step approach outlined in
the previous section. against the following attack types listed in Table 2.1:
Step 2: Construct a Basic Set of Malicious Behavior Step 3: Design Security Architecture Against Previous Behavior Set Step 4: Prove the Security of Architecture Step 6: Make Security Architecture Extensible The first tier of security in Java is the language design itself--the syntactical
and semantic constructs allowed by the language. The following is an examination
of Java language design constructs with a bearing on security. Final Classes and Methods Strong Typing and Safe Typecasting No Pointers Language Syntax for Thread-Safe Data Structures Unique Object Handles At compile time, all of the security mechanisms implied by the Java language syntax
and semantics are checked, including conformance to private and public declarations,
type-safeness, and the initialization of all variables to a guaranteed known value.
Namespace Encapsulation Very Late Linking and Binding The default mechanism of runtime loading of Java classes is to fetch the referred
class from a file on the local host machine. Any other way of loading a class--including
from across the network--requires an associated ClassLoader. A ClassLoader
is a subtype of the standard Java ClassLoader class that has methods that
implement all of the consistency and security mechanisms and apply them to every
class that is newly loaded. For security reasons, the ClassLoader cannot make any assumptions about
the bytecode. The bytecode could have been created from a Java program compiled with
the Java compiler, or it could have been created by a C++ compiler modified to generate
Java bytecode. This means the ClassLoader kicks in only after the incoming
bytecode has been verified. ClassLoader has the responsibility of creating a namespace for downloaded
code and resolving the names of classes referenced by the downloaded code. The ClassLoader
enforces package-delimited namespaces. The major source of security threats from and to Java programs is Java code that
comes in from across the network and executes on the client machine. This class of
transportable Java programs is called the Java applet class. A Java applet
has a very distinct set of capabilities and restrictions within the language framework,
especially from the security standpoint. The previous strict set of restrictions on access to a local file system applies
to applets running under Netscape Navigator 3.0 versions. The JDK 1.0 Appletviewer
slightly relaxes the restrictions by letting the user define a specific, explicit
list of files that can be accessed by applets. System Information Access From a security standpoint, locally loaded applets can:
Having examined the issue of security of executable content both in general and
specifically in the framework of Java, you now examine some aspects of security that
are not fully addressed by the current version of the Java architecture. You also
learn if, for some types of threats, 100 percent security can be achieved. The following components of the Java architecture are the loci of security mechanisms:
However, security provided by each of these layers can be diluted or defeated
in some ways with varying degrees of difficulty:
Security issues that cannot easily be addressed within Java (or any other mechanism
of executable content, for that matter) include:
One generic way to deal with security problems is for Java applet classes
to be sent encrypted and digitally signed. The ClassLoader, SecurityManager,
and even the bytecode verifier can include built-in decryption and signature verification
methods.
NOTE: These and other open issues related to Java security are topics of
ongoing debate and exploration of specific and involved security breach scenarios,
especially on online forums. The next and final section of this chapter points to
references and sources of further information on this topic.
In this section you find some excellent resources available online that reference
the Java language and network security. The wealth of information available in UseNet
groups is incredible. No matter what questions you may have, feel free to post them,
as chances are someone else knows the answer or at least where to refer you to find
the answer. comp.lang.java.*
The comp.lang.java.* groups are an excellent resource of information and
support. JavaSoft watches these groups closely, and often posts announcements of
new releases, bugs, and beta programs.
The Java Application Programming Interface, or API, is a set of
classes developed by Sun for use with the Java language. It is designed to assist
you in developing your own classes, applets, and applications. With these sets of
classes already written for you, you can write an application in Java that is only
a few lines long, as opposed to an application that would be hundreds of lines long
if it were written in C. Which would you rather debug? The classes in the Java API are grouped into packages, each of which may have
several classes and interfaces. Furthermore, each of these items may also have several
properties, such as fields and/or methods. While it is possible to program in Java without knowing too much about the API,
every class that you develop will be dependent on at least one class within the API,
with the exception of java.lang.Object, which is the superclass of all other
objects. Consequently, when you begin to develop more complex programs that deal
with strings, sockets, and graphical interfaces, it is extremely helpful for you
to know the objects provided to you by Sun, as well as the properties of these objects.
TIP: I suggest downloading the Core API in HTML format from JavaSoft and
reading through it to really get a good feel of how the language works. As you go
through each package, you will begin to understand how easy to use and powerful an
object-oriented language like Java can be.
The Core API is the API that is currently shipped with Java 1.1. These packages
make up the objects that are guaranteed to be available, regardless of the Java implementation:
NOTE: Those packages that were added under 1.1 are only guaranteed to be
available on machines supporting the 1.1 API.
The java.lang package consists of classes that are the core of the Java language.
It provides you not only with the basic data types, such as Character and
Integer, but also the means of handling errors through the Throwable
and Error classes. Furthermore, the SecurityManager and System
classes supply you with some degree of control over the Java Run-Time System. See Chapter 26, "java.lang," to learn
more about java.lang.
The java.io package serves as the standard input/output library for the Java language.
This package provides you with the ability to create and handle streams of data in
several ways. It provides you with types as simple as a String and as complex
as a StreamTokenizer. See Chapter 32, "java.io," to learn more.
The java.util package is composed essentially of a variety of useful classes that
did not truly fit in any one of the other packages. Among these handy classes are:
See Chapter 33, "java.util," to learn
more about the java.util package.
The java.net package is the package that makes Java a networked-based language.
It provides you with the capability to communicate with remote sources by creating
or connecting to sockets or using URLs. For example, you can write your own Telnet,
Chat, or FTP clients and/or servers by using this package.
The java.awt package is also known as the Java Abstract Window Toolkit
(AWT). It consists of resources that enable you to create rich, attractive,
and useful interfaces in your applets and stand-alone applications. The AWT not only
contains managerial classes, such as GridBagLayout, but it also has several
concrete interactive tools, such as Button and TextField. More
importantly, however, is the Graphics class that provides you with a wealth
of graphical abilities, including the ability to draw shapes and display images.
The java.awt.image package is closely related to the java.awt package. This package
consists of tools that are designed to handle and manipulate images coming across
a network. See Chapter 31, "java.awt.image," to learn
more.
The java.awt.peer is a package of interfaces that serve as intermediaries between
your code and the computer on which your code is running. You probably won't need
to work directly with this package.
The java.applet package is the smallest package in the API, but it is also the
most notable as a result of the Applet class. This class is full of useful
methods, as it lays the foundation for all applets and is also able to provide you
with information regarding the applet's surroundings via the AppletContext
interface.
The following packages were added to Java during the 1.1 upgrade. java.awt.event
NOTE: Printed documentation for all of the APIs is available from the JavaSoft
Web site at http://www.javasoft.com.
The Java Enterprise API supports connectivity to enterprise databases and legacy
applications. With these APIs, corporate developers are building distributed client/server
applets and applications in Java that run on any OS or hardware platform in the enterprise. Java Database Connectivity, or JDBCTM, is a standard SQL database
access interface that provides uniform access to a wide range of relational databases.
I am sure you have heard of ODBC. Sun has left no stone unturned in making Java applicable
to every standard in the computing industry today. Java IDL is developed to the OMG Interface Definition Language specification as
a language-neutral way to specify an interface between an object and its client on
a different platform. Java RMI is remote-method invocation between peers or the client and server when
applications at both ends of the invocation are written in Java.
The JavaCommerce API brings secure purchasing and financial management to the
Web. JavaWallet is the initial component, which defines and implements a client-side
framework for credit card, debit card, and electronic cash transactions. Just imagine--surfing
the Internet will take up all of your spare time...and money!
Java Server API is an extensible framework that enables and eases the development
of a whole spectrum of Java-powered Internet and intranet servers. The Java Server
API provides uniform and consistent access to the server and administrative system
resources. This API is required for developers to quickly develop their own Java
servlets--executable programs that users upload to run on networks or servers.
The Java Media API easily and flexibly allows developers and users to take advantage
of a wide range of rich, interactive media on the Web. The Media Framework has clocks
for synchronizing and media players for playing audio, video, and MIDI. 2-D and 3-D
provide advanced imaging models. Animation provides for motion and transformations
of 2-D objects. Java Share provides for sharing of applications among multiple users,
such as a shared white board. Finally, Telephony integrates the telephone with the
computer. This API is probably the most fun of all to explore.
The Java Security API is a framework for developers to include security functionality
easily and securely in their applets and applications. This functionality includes
cryptography with digital signatures, encryption, and authentication.
Java Management API provides a rich set of extensible Java objects and methods
for building applets that can manage an enterprise network over the Internet and
intranets. It has been developed in collaboration with SunSoft and a broad range
of industry leaders including AutoTrol, Bay Networks, BGS, BMC, Central Design Systems,
Cisco Systems, Computer Associates, CompuWare, LandMark Technologies, Legato Systems,
Novell, OpenVision, Platinum Technologies, Tivoli Systems, and 3Com.
The Java Beans API defines a portable, platform-neutral set of APIs for software
components. Java Bean components will be able to plug into existing component architectures,
such as Microsoft's OLE/COM/Active-X architecture, OpenDoc, and Netscape's LiveConnect.
End users will be able to join Java Beans components using application builders.
For example, a button component could trigger a bar chart to be drawn in another
component, or a live data feed component could be represented as a chart in another
component. (Java Beans is currently an internal code name.)
The Java Embedded API specifies how the Java API may be subsetted for embedded
devices that are incapable of supporting the full Java Core API. It includes a minimal
embedded API based on java.lang, java.util, and parts of java.io. It then defines
a series of extensions for particular areas, such as networking and GUIs.
Potential Vulnerability
Targets
Damage Integrity
Smuggle
InformationLock Up/
Deny UsageSteal
ResourceNonfatal Distraction
Impersonate
File system
X
X
X
X
X
Confidential data
X
X
X
X
X
Network
X
X
X
X
X
CPU
X
X
X
Memory
X
X
X
X
Output devices
X
X
X
X
Input devices
X
X
X
OS, program state
X
X
X
X
Java Approach to Security
Step 1: Visualize All Attack Scenarios
Step 5: Restrict Executable Content to Proven Secure Architecture Security at the Java Language Level
Strict Object-Orientedness
Security in Compiled Java Code
Class Version and Class File Format Verification
Bytecode Verification
Java Runtime System Security
Automatic Garbage Collection and Implicit Memory Management
SecurityManager Class
Security of Executable Code
File System and Network Access Restrictions
External Code Access Restrictions
Key
Information Returned
java.version
Java version number
java.vendor
Java vendor-specific string
java.vendor.url
Java vendor URL
java.class.version
Java class version number
os.name
Operating system name
os.arch
Operating system architecture
file.separator
File separator (such as /)
path.separator
Path separator (such as :)
line.separator
Line Separator
Inaccessible System Information
Key
Information Returned
java.home
Java installation directory
java.class.path
Java classpath
user.name
User's account name
user.home
User's home directory
user.dir
User's current working directory
Applets Loaded from the Local Client
Open Issues
References and Resources on Java and Network Security
UseNet Newsgroups
The Java API
The following list contains several APIs outside of the core API that are available
or under development:
Java Core API
java.lang
java.io
java.util
java.net
java.awt
java.awt.image
java.awt.peer
java.applet
New to 1.1
java.awt.datatransfer
See Chapter 28, "java.awt--Events," to learn
more about the java.awt.event package.
java.corba and java.corba.orb
See Chapter 37, "JavaIDL: A Java Interface to CORBA,"
to learn more about CORBA.
java.rmi, java.rmi.registry and java.rmi.server
See Chapter 40, "Remote Method Invocation,"
to learn more about RMI.
java.lang.reflect
See Chapter 20, "Reflection," to learn more.
java.security, java.security.acl, and java.security.interfaces
See Chapter 36, "Java Security in Depth," to
learn more about the java.security packages.
java.sql
See Chapters 43-45 to learn more about JDBC.
Java Enterprise API
Java Commerce API
Java Server API
Java Media API
Java Security API
Java Management API
Java Beans API
Java Embedded API