Sunday, December 5, 2010

Secure your Java apps from end to end

Nobody was ever fired for writing insecure code. My slightly reworked version of the popular adage, "Nobody was ever fired for buying IBM," while not exactly true is accurate enough to be alarming. Employers more concerned about hitting deadlines at Internet speed and employees more interested in adding more bullet items to their resumes often push security out of the picture.


Consider another alarming phenomenon: When I talk with managers and engineers about security, I often discover that they operate under the misconception that they don't need to worry about security because "Java is secure." By accepting this faulty notion, engineers fail to acknowledge that in building Java apps, they must consider security from three different contexts: virtual machine security, application security, and network security. Java is secure out of the box in only one of those contexts: virtual machine security.
In this series of articles, I will attempt to correct this dangerous misconception. To do so, I will examine Java security from within each of the three contexts and illustrate how common security flaws cut across each. I will also describe defensive measures that you can employ to create more secure applications.

Three flavors of security

When Java made its public debut, developers, researchers, and journalists made a lot of noise about its security. In those early days, Java security meant byte code and virtual machine security. Since Java was mainly seen as a language for downloading small applications to be executed locally, the downloaded code's integrity and execution environment were of paramount importance. Security in that context meant installing a correctly functioning class loader and security manager, and verifying downloaded code.
In my years of building C and C++ applications I never worried about virtual machine security -- it stepped into the limelight with Java. When I thought about security, I worried about flaws in the application logic or implementation that compromised the application or the system on which the application ran. In C++, security in theapplication context involved limiting the scope of setuid code (in the Unix environment, setuid code runs as another user -- typically the superuser) and trying to avoid introducing buffer overruns and other types of stack nastiness.
The introduction of distributed applications brought another aspect of security to the table. As its name suggests, a distributed application is composed of many parts; each part might reside on its own machine and might communicate with other parts over a public network. A Web application is the stereotypical example. Security in a network context means authenticating and authorizing users and application components and encrypting communication channels.
Many developers do not see the differences between the contexts I have described above and assume that because Java is secure at the virtual machine level, applications are secure across the board. I hope to correct that belief. I'll begin by discussing virtual machine security.

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:

Method void main(java.lang.String[])
     0 new #3 <class java.lang.Float>
     3 dup
     4 ldc2_w #13 <Double 56.78>
     7 invokespecial #8 <Method java.lang.Float(double)>
    10 astore_1
    11 new #4 <Class java.lang.Integer>
    14 dup
    15 sipush 1234
    18 invokespecial #9 <Method java.lang.Integer(int)>
    21 astore_2
    22 getstatic #10 <Field java.io.PrintStream out>
    25 aload_1
    26 invokevirtual #12 <Method java.lang.String toString()>
    29 invokevirtual #11 <Method void println(java.lang.String)>
    32 return


The listing above contains the main() method's disassembled output. At byte code offset 25 in this method, the virtual machine loads a reference to an instance of Float that was created earlier (at offsets 0 to 10). That is the instruction we will modify. The disassembled output of the modified class is below:
Method void main(java.lang.String[])
     0 new #3 <Class java.lang.Float>
     3 dup
     4 ldc2_w #13 <Double 56.78>
     7 invokespecial #8 <Method java.lang.Float(double)>
    10 astore_1
    11 new #4 <Class java.lang.Integer>
    14 dup
    15 sipush 1234
    18 invokespecial #9 <Method java.lang.Integer(int)>
    21 astore_2
    22 getstatic #10 <Field java.io.PrintStream out>
    25 aload_2
    26 invokevirtual #12 <Method java.lang.String toString()>
    29 invokevirtual #11 <Method void println(java.lang.String)>
    32 return


The class is identical byte for byte except for the instruction at offset 25, which loads a reference to an instance of theInteger class.
It is important to note that the result is still valid byte code, meaning the JVM can still execute the byte code without dumping core or heading off into space. The verifier, however, can tell that something has changed under the hood. On my system, I receive the following error when I try to load the class:
Exception in thread "main" java.lang.VerifyError:
  (class: Test1, method: main signature: ([Ljava/lang/String;)V)
  Incompatible object argument for function call


If you turn the verifier off or if you could exploit a virtual machine flaw and pass the code by the verifier in systems in the wild, the illegal and possibly subversive code works. If I execute the command below I receive the answer 1234 -- the value of theInteger instance.
java -noverify Test1


That example is as innocuous as can be, but the potential for harm is real enough. Techniques like those presented above, in conjunction with a virtual machine flaw that allows unverified code to be executed, make type confusion exploits possible.

Type confusion

The notion of type is integral to the Java programming language. Every value has an associated type, and the JVM uses its knowledge of a value's type to determine the set of operations that can be performed on the value.
Consistent application of type information is essential for virtual machine security. A type confusion attack, enabled by the introduction of malicious and unverified code, attempts to undermine this foundation of Java security by fooling the JVM into thinking that a block of memory representing one class instance is really an instance of another class. If the attack is successful, the application can then manipulate the instance's state in ways the class's designer never intended. That assault is called a type confusion attack because the virtual machine becomes confused as to the type of the compromised class.
If a class is properly verified, type confusion should never be possible. In the second listing above, the verifier caught the attempt and threw a VerifyError. As long as the verifier isn't turned off or bypassed, security is assured.
Fortunately, the last flaw in the Java byte code verifier of which I am aware was discovered and fixed in late 1999. Given this fact, you might assume you aren't in immediate danger; however, you'd be assuming too much.
While flaws are becoming few and far between, ample opportunity remains for slipping unverified code into an application. Remember, you can manually turn verification off. In the last two months I've come across three major Java applications that instruct the user to turn verification off in certain circumstances. One of those applications even has a significant RMI (remote method invocation) component (as you will learn later in the series, RMI allows network class loading to occur at places in applications that you might not expect). If you can avoid it, don't turn verification off.

Be assured

JVM security is an important facet of overall security. The discussion of unverified code and type confusion exploits should help you understand why. Without the assurance of properly verified downloaded code and a type system on which you can depend, secure computing of any kind is not possible.
Next month, I will explore another context of Java security: application security.

About the author

Todd Sundsted has been writing programs since computers became available in desktop models. Though originally interested in building distributed applications in C++, Todd moved on to the Java programming language when it became the obvious choice for that sort of thing. In addition to writing, Todd is cofounder and chief architect of PointFire, Inc.


Wednesday, December 1, 2010

Memory Usage in Java

In Java, memory is allocated in various places such as the stack, heap, etc. In this newsletter I'm only going to look at objects which are stored on the heap. Please don't take me to task for not mentioning the others, they might appear in a future newsletter.

Say I have a class Foo, how much memory will one instance of that class take? The amount of memory can be determined by looking at the data members of the class and all the superclasses' data members. The algorithm I use works as follows:
  1. The class takes up at least 8 bytes. So, if you say new Object(); you will allocate 8 bytes on the heap.
  2. Each data member takes up 4 bytes, except for long and double which take up 8 bytes. Even if the data member is a byte, it will still take up 4 bytes! In addition, the amount of memory used is increased in 8 byte blocks. So, if you have a class that contains one byte it will take up 8 bytes for the class and 8 bytes for the data, totalling 16 bytes (groan!).
  3. Arrays are a bit more clever, at least smaller primitives get packed. I'll deal with these later.
In order to be able to test many different types of objects, I have written a MemoryTestBench class that takes an ObjectFactory which is able to create the type of object that you want to test. The MemoryTestBench can either tell you how many bytes are used by that object or it can print out a nicely formatted result for you. You get the most accurate results if you make sure that supplementary memory is already allocated when you start counting. I therefore construct the object, call the methods for finding the memory, and then set the handle to null again. The garbage collector is then called many times, which should free up all unused memory. The memory is then counted, the object created, garbage collected, and the memory counted again. The difference is the amount of memory used by your object, voila!
public class MemoryTestBench {
  public long calculateMemoryUsage(ObjectFactory factory) {
    Object handle = factory.makeObject();
    long mem0 = Runtime.getRuntime().totalMemory() -
      Runtime.getRuntime().freeMemory();
    long mem1 = Runtime.getRuntime().totalMemory() -
      Runtime.getRuntime().freeMemory();
    handle = null;
    System.gc(); System.gc(); System.gc(); System.gc();
    System.gc(); System.gc(); System.gc(); System.gc();
    System.gc(); System.gc(); System.gc(); System.gc();
    System.gc(); System.gc(); System.gc(); System.gc();
    mem0 = Runtime.getRuntime().totalMemory() -
      Runtime.getRuntime().freeMemory();
    handle = factory.makeObject();
    System.gc(); System.gc(); System.gc(); System.gc();
    System.gc(); System.gc(); System.gc(); System.gc();
    System.gc(); System.gc(); System.gc(); System.gc();
    System.gc(); System.gc(); System.gc(); System.gc();
    mem1 = Runtime.getRuntime().totalMemory() -
      Runtime.getRuntime().freeMemory();
    return mem1 - mem0;
  }
  public void showMemoryUsage(ObjectFactory factory) {
    long mem = calculateMemoryUsage(factory);
    System.out.println(
      factory.getClass().getName() + " produced " +
      factory.makeObject().getClass().getName() +
      " which took " + mem + " bytes");
  }
}
The ObjectFactory interface looks like this:
public interface ObjectFactory {
  public Object makeObject();
}

Basic Objects

Let's start with the easiest case, a BasicObjectFactory that simply returns a new instance of Object.
public class BasicObjectFactory implements ObjectFactory {
  public Object makeObject() {
    return new Object();
  }
}
When we run this, we get the following output:
BasicObjectFactory produced java.lang.Object which took 8 bytes

Bytes

I suggested earlier that bytes are not packed in Java and that memory usage is increased in 8 byte blocks. I have written the ByteFactory and the ThreeByteFactory to demonstrate this:
public class ByteFactory implements ObjectFactory {
  public Object makeObject() {
    return new Byte((byte)33);
  }
}

public class ThreeByteFactory implements ObjectFactory {
  private static class ThreeBytes {
    byte b0, b1, b2;
  }
  public Object makeObject() {
    return new ThreeBytes();
  }
}
When we run these, we get the following output:
ByteFactory produced java.lang.Byte which took 16 bytes
ThreeByteFactory produced ThreeByteFactory$ThreeBytes which took 24 bytes
This is great (not). When I first started using Java I used to spend hours deciding whether a variable should be an int or short or a byte in order to minimize the memory footprint. I was wasting my time.As I said earlier, I don't know if this is only a problem under NT or if it's the same on all platforms. Knowing Java's dream of being equally inefficient on all platforms, I suspect that it would be the same.

Booleans

Let's carry on and look at a smaller unit of information, the boolean. Now a boolean is simply a bit, true or false, yes or no, zero or one. If I have a class that contains 64 booleans, guess how much memory it will take? 8 for the class, and 4 for each of the boolean data members, i.e. 264 bytes!!! Since a boolean is essentially the same as a bit, we could have stored the same information in one long. If you don't believe me, have a look at the following class:
public class SixtyFourBooleanFactory implements ObjectFactory {
  private static class SixtyFourBooleans {
    boolean a0, a1, a2, a3, a4, a5, a6, a7;
    boolean b0, b1, b2, b3, b4, b5, b6, b7;
    boolean c0, c1, c2, c3, c4, c5, c6, c7;
    boolean d0, d1, d2, d3, d4, d5, d6, d7;
    boolean e0, e1, e2, e3, e4, e5, e6, e7;
    boolean f0, f1, f2, f3, f4, f5, f6, f7;
    boolean g0, g1, g2, g3, g4, g5, g6, g7;
    boolean h0, h1, h2, h3, h4, h5, h6, h7;
  }
  public Object makeObject() {
    return new SixtyFourBooleans();
  }
}
When we run this, we get the following output:
SixtyFourBooleanFactory produced SixtyFourBooleanFactory$SixtyFourBooleans
  which took 264 bytes
Admittedly, the example was a little bit contrived, as you would seldom have that many booleans in one class, but I hope you get the idea.
Sun must have realised this problem so they made constants in java.lang.Boolean for TRUE and FALSE that both contain instances of java.lang.Boolean. I think that the constructor for Boolean should have been private to stop people from creating 16 byte objects that are completely unnecessary.

Arrays of Boolean Objects

A Boolean Array takes up 16 bytes plus 4 bytes per position with a minimum of 8 bytes at a time. In addition to that, we obviously have to count the actualy space taken by Boolean objects.
public class BooleanArrayFactory implements ObjectFactory {
  public Object makeObject() {
    Boolean[] objs = new Boolean[1000];
    for (int i=0; i<objs.length; i++)
      objs[i] = new Boolean(true);
    return objs;
  }
}
Try guess how many bytes would be taken up by a Boolean array of size 1000 with Boolean objects stuck in there. Ok, I'll help you: 16 + 4*1000 (for the pointers) + 16*1000 (for the actual Boolean objects) = 20016. Run the code and see if I'm right ;-) If we, instead of making a new Boolean object each time, use the Flyweights provided in Boolean, we'll get to 16 + 4*1000 = 4016 bytes used.
Primitives get packed in arrays, so if you have an array of bytes they will each take up one byte (wow!). The memory usage of course still goes up in 8 byte blocks.
public class PrimitiveByteArrayFactory implements ObjectFactory {
  public Object makeObject() {
    return new byte[1000];
  }
}
When we run this, we get the following output:
PrimitiveByteArrayFactory produced [B which took 1016 bytes

java.lang.String

Strings actually fare quite well since they can be "internalised" meaning that only one instance of the same String is kept. If you, however, construct your String dynamically, it will not be interned and will take up a bit of memory. Inside String we find:
// ...
private char value[];
private int offset;
private int count;
private int hash = 0;
// ...
Say we want to find out how much "Hello World!" would take. We start adding up 8 (for the String class) + 16 (for the char[]) + 12 * 2 (for the characters) + 4 (value) + 4 (offset) + 4 (count) + 4 (hash) = 64 bytes. It's quite difficult to measure this, as we have to make sure the String is not internalized by the JVM. I used the StringBuffer to get this right:
public class StringFactory implements ObjectFactory {
  public Object makeObject() {
    StringBuffer buf = new StringBuffer(12);
    buf.append("Hello ");
    buf.append("World!");
    return buf.toString();
  }
}
When we run this, we get, as expected, the following output:
StringFactory produced java.lang.String which took 64 bytes

java.util.Vector

Now we get to the real challenge: How much does a java.util.Vector use in memory? It's easy to say, now that we have a MemoryTestBench, but it's not so easy to explain. We start by looking inside the java.util.Vector class. Inside we find the following:
// ...
protected Object elementData[];
protected int elementCount;
// ...
Using the knowledge we already have, we decide that the amount of memory used will be 8 (for the class) + 4 (for the pointer to elementData) + 4 (for elementCount). The elementData array will take 16 (for the elementData class and the length) plus 4 * elementData.length. We then follow the hierarchy up and discover the variable int modCount in the superclass java.util.AbstractList, which will take up the minimum 8 bytes. For a Vector of size 10, we will therefore take up: 8 + 4 + 4 + 16 + 4*10 + 8 = 80 bytes, or simply 40 + 4*10 = 80 bytes, which agrees with our experiment:
public class VectorFactory implements ObjectFactory {
  public Object makeObject() {
    return new java.util.Vector(10);
  }
}
When we run this, we get the following output:
VectorFactory produced java.util.Vector which took 80 bytes
So, what happens when we create a JTable with a DefaultTableModel with 100x100 cells? The DefaultTableModel keeps a Vector of Vectors so this will take 40 + 4*100 + (40 + 4*100) * 100 = 440 + 44000 = 44440 bytes just for the empty table. If we put an Integer in each cell, we will end up with another 100*100*16 = 160'000 bytes used up.

java.util.LinkedList

What's better, a java.util.LinkedList or a java.util.ArrayList? Experienced followers of these newsletters will of course say: "Neither, the CircularArrayList is better" ;-). Let's see what happens when we put 10000 objects into an ArrayList (which uses the same amount of memory as the Vector) vs. a LinkedList. Remember that each Object takes up 8 bytes, so we will subtract 80000 bytes from each answer to get comparable values:
import java.util.*;
public class FullArrayListFactory implements ObjectFactory {
  public Object makeObject() {
    ArrayList result = new ArrayList(10000);
    for (int i=0; i<10000; i++) {
      result.add(new Object());
    }
    return result;
  }
}

import java.util.*;
public class FullLinkedListFactory implements ObjectFactory {
  public Object makeObject() {
    LinkedList result = new LinkedList();
    for (int i=0; i<10000; i++) {
      result.add(new Object());
    }
    return result;
  }
}
When we run this, we get the following output:
FullArrayListFactory produced java.util.ArrayList which took 120040 bytes
FullLinkedListFactory produced java.util.LinkedList which took 320048 bytes
When we subtract 80000 bytes from each, we find that the ArrayList takes up 40040 bytes (as expected) and the LinkedList uses 240048 bytes. How many of us consider issues like this when we code?
We have come to the end of yet another newsletter. I am trying to put newsletters together that will be worthwhile to send out, so as a result they will not always appear every week, unless I feel particularly