|
|
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 3 of 4
Virtual machine security, the longtime focus of all developers' attentions, is almost a nonissue today. The number of VM-related security flaws has dropped precipitously in the last two years. Surprises certainly lurk in the wings, especially as Java finds itself implemented on an immensely heterogeneous line of micro devices via Java 2 Platform, Micro Edition technology, but the worst has past.
I was initially tempted to discuss virtual machine security only briefly before moving along to application and network security. I decided to give it equal time for two important reasons: First, excellent programming lessons lie hidden within the numerous flaws discovered over the past six years. Second, many security flaws operate across the three contexts that I described. To understand their behavior, you must be familiar with all three contexts, including JVM security.
If you examine the types of security vulnerabilities identified over the past six years (see Resources for the "official" list), you will find that they fall into a handful of categories. As far as virtual machine security is concerned, the two most important types of flaws revolve around the introduction of unverified and possibly illegal byte code, and the subversion of the Java type system. In exploits, the two are often used together.
When the JVM loads a class file from a server across the network, it has no way of knowing whether or not the byte code is safe to execute. Safe byte code never instructs the virtual machine to perform operations that would leave the Java runtime in an inconsistent or invalid state.
Normally the Java compiler ensures that the byte code in the class files it creates is safe. It's possible to create byte code by hand that attempts to accomplish tasks Sun's Java compiler would never let you do. The Java verifier examines all such application byte code and, using a fancy set of heuristics, identifies code that doesn't play by the rules. Once byte code is verified, the virtual machine knows that it's safe to execute -- at least as long as the verifier is functioning correctly.
Let's take a look at an example in order to better understand the role the verifier plays and to see why trouble reigns when it fails to function.
Consider the following class:
public
class Test1
{
public
static
void
main(String [] arstring)
{
Float a = new Float(56.78);
Integer b = new Integer(1234);
System.out.println(a.toString());
}
}
If you compile and run that class, the application will print the string 56.78 to the console. That is the value assigned to the instance of the Float class. We are going to modify one byte of the class's byte code and attempt to trick the virtual machine into invoking the
toString() method on Integer class's instance rather than on Float's instance (you can download the original and the modified class files from Resources).
Let's take a look at the disassembled output of the unmodified class file: