Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

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

Secure your Java apps from end to end, Part 1

The foundation of Java security: Virtual machine and byte code security

  • Print
  • Feedback

Page 3 of 4

The foundation: Virtual machine security

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.

The secret of unverified code

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:

  • Print
  • Feedback

Resources