http://www.developer.com/design/article.php/3657951/Java-Language-Integrity-amp-Security-Serializing-Classes.htm
This series, The Object-Oriented Thought Process, is intended for someone just learning an object-oriented language and who wants to understand the basic concepts before jumping into the code, or someone who wants to understand the infrastructure behind an object-oriented language he or she is already using. These concepts are part of the foundation that any programmer will need to make the paradigm shift from procedural programming to object-oriented programming. Click here to start at the beginning of the series. In keeping with the code examples used in the previous articles, Java will be the language used to implement the concepts in code. One of the reasons that I like to use Java is because you can download the Java compiler for personal use at the Sun Microsystems Web site http://java.sun.com/. You can download the standard edition, J2SE 5.0, at http://java.sun.com/j2se/1.5.0/download.jsp to compile and execute these applications. I often reference the Java J2SE 5.0 API documentation and I recommend that you explore the Java API further. Code listings are provided for all examples in this article as well as figures and output (when appropriate). See the first article in this series for detailed descriptions for compiling and running all the code examples. In the previous column, you explored some of the behaviors of dynamically loaded classes as they relate to the topics of performance and security, http://www.developer.com/java/data/article.php/3652286. Specifically, you attempted to insert a rogue class into the loading process to see whether you could compromise the integrity of the class loading process. In this article, you will expand this concept within the constraints of a client/server model. The code examples in this series are meant to be a hands-on experience. There are many code listings and figures of the output produced from these code examples. Please boot up your computer and run these exercises as you read through the text. Please revisit an earlier article in this series, "Serializing an Object via a Client/Server Connection," to provide you with an example that you can use to illustrate this month's topic. Diagram 1 shows the basic framework that you will use for this example. There are three files in this example: Employee.java, Server.java, and Client.java. Diagram 1: Client/Server Framework The basic concept is this: You create a class called Employee as seen in Listing 1. In this case, you prune the class significantly from the example in the earlier article so that you can concentrate on the concept of loading the class. Listing 1: The Employee Class Likewise, you can adjust the code in the client and server to correspond with the lighter version of the Employee class. The complete code for the Client class is shown in Listing 2. Listing 2: The Client Class The complete code for the Server class is shown in Listing 3. Listing 3: The Server Class For a detailed description of the code contained in Server.java and Client.java, please refer to the article referenced earlier: http://www.developer.com/design/article.php/3597071. I used a Command Prompt to compile the code. On certain machines, it is called a DOS Shell; on others, it is called a Command Prompt. You can open a Command Prompt in the Programs->Accessories option area. Type the following code at the command prompt to compile all three of the files. I created a batch file called make.bat to handle this so I don't have to keep typing in these lines of code. Thus, all I have to do is type out the word make at the C: prompt like this: This command will invoke the make.bat file and execute the following lines of code. Figure 1 shows the screen shot of what happens when this batch file is executed and the Java files are compiled. Figure 1: Compiling the Code At this point, you now will have three class files: Employee.class, Server.class, and Client.class. Employee.class is the class that will be sent over the network; Client.class and Server.class represent the client and server applications respectively. These files are seen in Figure 2. Figure 2: The application code In one of the DOS Shells, type the following line at the command prompt: Figure 3 shows what happens in Command Prompt. Figure 3: Starting the Server If everything is working properly, the "Server Waiting" message is displayed. At this point, you can start the Client. In a separate DOS Shell, start the Client with the following line. The result is shown in Figure 4. Figure 4: Starting the Client If all is well, you will see that the employeeNumber has been updated by the server. The original value of 150 was sent to the server by the client. The server then updated the employeeNumber and sent that value back to the client—which then prints it. You can put some specific identification in the print statements to provide further assurance. With the circuit complete, the Server should exit cleanly, as shown in Figure 5. Figure 5: Completing the System Now that the framework for this example is in place, explore a situation that may cause some application integrity and security issues. It is important to note that the both Client.java and Server.java use the same definition of the Employee class. The Client instantiates the actual Employee object: Whereas the Server creates an Employee reference and uses this as a handle to the Employee object that comes off the network connection; see Diagram 2. Diagram 2: Passing the Employee object This represents one of the beauties of dynamically loading classes; the Server can accept a valid Employee object from any Client that chooses to send it one. The operative term here is valid. As you saw in the previous article, the Employee class definition can change without that update being reflected in the Employee class definition that the Server is using. In other words, what happens if the Client and Server both start off with the same Employee class definition but the Client decides to change the Employee class without broadcasting the change to the Server? See what happens. To illustrate this, you need to move the Server into a separate directory. The reason for this provides a good demonstration of how classes are dynamically loaded. First, change the Employee class by adding another attribute, the added attribute employeeName in Listing 4. Listing 4: The Updated Employee Class Now, recompile the example; however, do not recompile the Server. This is simple to do by using the rem Command Prompt keyword. This keyword treats the line as a remark, or comment, and will not execute it. Now, execute the complete system in the exact same way as you did earlier in the article. You should get the exact same results. This may seem surprising because you did not recompile the Server to reflect the change in the Client. However, don't forget that the Employee class definition was recompiled and that the Server loads it dynamically—thus, the Server actually did pick up the new version. To really check what happens if the Client and Server have different versions of the Employee class, you need to separate the Server from the Client and make sure that they truly have different versions of the Employee class. To accomplish this, you can simply create a new directory, call it Server, and place a copy of the original version of the Server and Employee class in this directory. This setup is shown in Figure 6. Note that the only files in this directory are the original version of the Employee class, the Server, and the batch file that starts the Server. Figure 6: The Separate Server Directory Now return to the directory that contains the entire application, The Employee object and the Client include the updated code with the following line—this is absent in the code inside the new server directory. Now, you can start up the Server application from the new directory as seen in Figure 7. Figure 7: Starting the Original Server While the Server waits, you now complete the process by starting up the Client with the updated code as seen in Figure 8. Note that the Client application now throws an exception. Figure 8: Starting the Original Server The Server also encounters a problem; in fact, it crashes. You get the message: Figure 9: The Server Crashes This message is generated because the serialVersionUID of the classes do not match. The serialVersionUID is one of the measures used by the Java environment to keep rogue classes from getting inserted into systems. Before you spend time getting into detail about how objects are serialized, see what happens when you don't serialize an object. You may have noticed the following line of code in the Employee class. This is how the Sun documentation describes the Serializable interface. Serializability of a class is enabled by the class implementing the java.io.Serializable interface. Classes that do not implement this interface will not have any of their state serialized or deserialized. All subtypes of a serializable class are themselves serializable. The serialization interface has no methods or fields and serves only to identify the semantics of being serializable. To allow subtypes of non-serializable classes to be serialized, the subtype may assume responsibility for saving and restoring the state of the supertype's public, protected, and (if accessible) package fields. Perhaps the key phrase in this description is saving and restoring and that "the serialization interface has no methods or fields and serves only to identify the semantics of being serializable." You use the serialization interface to marshal objects over wires when writing to files, networks, and so forth. Now, eliminate the serialization interface from the Employee class as seen in Listing 5: Listing 5: The Updated Employee Class Compile all the code just as you did when you initially began with this example. When you start up the Server, you get business as usual; however, when you run the Client, you get the exception seen in Figure 10, java.io.NotSerializableException. Figure 10: The Client Crashes The NotSerializableException is described in the Java documentation as follows: Based on this exception, you see that you do need to serialize the Employee object by including the Serializable interface. Otherwise, you can't send the object across the network. Knowing that you need the Serializable interface is one thing; however, what is the Serializable interface and what actually does it do? You will explore this in a future article. In this article, you reconstructed an example from a previous column in this series and altered it to explain how classes are dynamically loaded over a network. You also demonstrated that there are some potential issues that may lead to compromises in the integrity and security of dynamically loaded classes. The mechanism for marshalling objects across a wire includes the use of the Serializable interface. You were able to see that if the Serializable interface was not included in the Employee class, an exception was generated—in short, you need to utilize the Serializable interface. In the future, you will explore the Serializable interface in much greater detail to see exactly what it does and how it is used. Matt Weisfeld is a faculty member at Cuyahoga Community College (Tri-C) in Cleveland, Ohio. Matt is a member of the Information Technology department, teaching programming languages such as C++, Java, C#, and .NET as well as various Web technologies. Prior to joining Tri-C, Matt spent 20 years in the information technology industry gaining experience in software development, project management, business development, corporate training, and part-time teaching. Matt holds an MS in computer science and an MBA in project management. Besides The Object-Oriented Thought Process, which is now in its second edition, Matt has published two other computer books, and more than a dozen articles in magazines and journals such as Dr. Dobb's Journal, The C/C++ Users Journal, Software Development Magazine, Java Report, and the international journal Project Management. Matt has presented at conferences throughout the United States and Canada.
Java Language Integrity & Security: Serializing Classes
February 5, 2007
The Code Example

import java.io.*;
import java.util.*;
public class Employee implements Serializable {
private int employeeNumber;
Employee(int num) {
employeeNumber = num;
}
public int getEmployeeNumber() {
return employeeNumber ;
}
public void setEmployeeNumber(int num) {
employeeNumber = num;
}
}
import java.io.*;
import java.net.*;
public class Client {
public static void main(String[] arg) {
try {
Employee joe = new Employee(150);
System.out.println("original employeeNumber= " +
joe.getEmployeeNumber());
Socket socketConnection = new Socket("127.0.0.1", 11111);
ObjectOutputStream clientOutputStream = new
ObjectOutputStream(socketConnection.getOutputStream());
ObjectInputStream clientInputStream = new
ObjectInputStream(socketConnection.getInputStream());
clientOutputStream.writeObject(joe);
joe= (Employee)clientInputStream.readObject();
System.out.println("updated employeeNumber= " +
joe.getEmployeeNumber());
clientOutputStream.close();
clientInputStream.close();
} catch (Exception e) {System.out.println(e); }
}
}
import java.io.*;
import java.net.*;
public class Server {
public static void main(String[] arg) {
Employee employee = null;
try {
ServerSocket socketConnection = new ServerSocket(11111);
System.out.println("Server Waiting");
Socket pipe = socketConnection.accept();
ObjectInputStream serverInputStream = new
ObjectInputStream(pipe.getInputStream());
ObjectOutputStream serverOutputStream = new
ObjectOutputStream(pipe.getOutputStream());
employee = (Employee)serverInputStream.readObject();
employee.setEmployeeNumber(256);
serverOutputStream.writeObject(employee);
serverInputStream.close();
serverOutputStream.close();
} catch(Exception e) {System.out.println(e);
}
}
}
Compiling the Code
C:column31> make
"C:Program FilesJavajdk1.5.0_06binjavac"
-classpath . Employee.java
"C:Program FilesJavajdk1.5.0_06binjavac"
-classpath . Client.java
"C:Program FilesJavajdk1.5.0_06binjavac"
-classpath . Server.java

Click here for a larger image.

Click here for a larger image.
Starting the Server
"C:Program FilesJavajdk1.5.0_06binjava" classpath . Server

Click here for a larger image.
Starting the Client
"C:Program FilesJavajdk1.5.0_06binjava" -classpath . Client

Click here for a larger image.

Click here for a larger image.
Causing Trouble
Employee joe = new Employee(150);

Separating the Server
import java.io.*;
import java.util.*;
public class Employee implements Serializable {
"C:Program FilesJavajdk1.5.0_06binjavac"
-classpath . Employee.java
"C:Program FilesJavajdk1.5.0_06binjavac"
-classpath . Client.java
rem "C:Program FilesJavajdk1.5.0_06binjavac"
-classpath . Server.java

Click here for a larger image.
C:column31>
private int employeeName;

Click here for a larger image.

Click here for a larger image.
java.io.InvalidClassException: Employee; local class incompatible:
stream classd
esc serialVersionUID = 8052846892556280666,
local class serialVersionUID = 75684
47985707181517

Click here for a larger image.
Note: I will discuss the serialization of objects in great detail in a later article.
Removing the Serializable Interface
public class Employee implements Serializable {
public interface Serializable
import java.io.*;
import java.util.*;
"C:Program FilesJavajdk1.5.0_06binjavac"
-classpath . Employee.java
"C:Program FilesJavajdk1.5.0_06binjavac"
-classpath . Client.java
"C:Program FilesJavajdk1.5.0_06binjavac"
-classpath . Server.java

Click here for a larger image.
public class NotSerializableException extends ObjectStreamException Thrown when an instance is required to have a Serializable interface. The serialization runtime or the class of the instance can throw this exception. Conclusion
Reference
About the Author