Mar 132007
 

Java deals with many of the security issues associated with arrays in languages such as C and C++, as it does not allow explicit usage of pointers. In C or C++, a programmer can control the array operations to a more minute level, thanks to the way pointers and arrays work together. But it can also lead to memory leaks.

For instance, if the programmer does not explicitly check the bounds of the array, the program can crash. The language itself does not provide any features to control this, and hands over this responsibility over to programmers.

Java, as we know, is quite different. It takes away some power from the programmer in terms of what the programmer can directly do with arrays, but then it also assumes greater responsibility at the language semantics level. It does not allow a programmer to cross the boundaries of an array and possibly access other parts of memory intentionally or otherwise. Because there are no pointers, a programmer cannot bypass the mechanism of accessing array members in the standard manner anyway.

Java assumes greater responsibility at the language semantics level…

However, there is an interesting security hole that an attacker can exploit, with reference to returning arrays during method calls. To understand this clearly, let us quickly review the basics of arrays in Java for the sake of completeness.

There is an interesting security hole with reference to returning arrays during method calls…

An array is essentially a list of variables of similar type. For creating an array, we need to create the array variable of the desired type. The basic declaration of an array takes the following form:

type array-variable-name [];

Here, type represents the base data type of the array. The type determines the data type of each element in the array. For instance, we can create an array of integers by using the following declaration:

int temperature [ ];

Although this declaration signifies that temperature is an array variable, at this juncture, no array actually exists. No memory is allocated for the storage of the array. Instead, temperature is set to null, which means an array with no value. We can conceptually think of it as a null pointer. We need to explicitly use the new operator if we want to link temperature to an array that will actually exist in memory.

The general syntax for doing this is as follows:

array-variable-name = new type [size];

This creates an array of the appropriate type, containing size number of elements. They can be accessed by making use of the array-variable-name with the appropriate array index. Extending the same example, we have:

temperature = new int [31];

This creates an array of 31 integers, all of which can be accessed by the name temperature, suffixed with the appropriate index. For example, temperature [5] provides us the 6th array value, as the index starts counting from 0. By default, Java automatically initializes all integer array members to 0.

In Java, arrays are implemented as objects…

This reiterates the fact that in Java, arrays are implemented as objects. Our following discussion considers arrays as an example and equally applies to objects of all kinds. However, to keep things simple, we shall only talk about arrays, and ignore other kinds of objects, because the same concepts can be applied there.

Now let us think about a Java class named Example. As we can see, the class declares a private integer array named innerData. The setData () method allocates memory for five integer members of this array and initializes the values of the array members using a for loop. The displayData () method simply displays the contents of the array. The getData () method returns the array to the calling method.

public class Example {

	private int innerData [];

	public int [] getData () {
		System.out.println ("Inside getData ...");
		return innerData;
	}

	void setData () {
		System.out.println ("Inside setData ...");
		innerData = new int [5];

		for (int i=0; i < innerData.length; i++)  {
			innerData [i] = i;
		}
	}

	void displayData () {
		System.out.println ("Inside displayData ...");
for (int i=0; i < innerData.length; i++) { System.out.println (innerData [i]); } } }

This seems to be quite fine. Let us compile this class. Then let us write another class named Tester to test the functionality of the above class.

public class Tester {

	public static void main (String args []) {

		Example example = new Example ();
		int arr []= new int [5];
		example.setData ();
		example.displayData ();
		arr = example.getData ();
		for (int i=0; i < arr.length; i++) {
				arr [i] = arr [i] * 10;
		}
		example.displayData ();
	}
}

Let us understand what we are trying to do here.

PAGE 1 OF 2

We first create an object of the Example class and name it as example. We then create a local array named arr, and allocate space for five integers in that array. We then call the setData () method on the example object. This should create space for five integers for the private array named innerData of the Example object. We then display the values of that array. Because we have initialized them in the setData () method of the example object to the value of the current for loop iteration index, the innerData array will have values 0, 1, 2, 3, and 4. We call the displayData () method on the example object to verify this. Note that innerData is private to the example object. It cannot be accessed inside the Tester class.

At this stage, we call getData () method of the example object. As we can see, this would cause the getData () method to return the values of the local array innerData, which will get assigned to the array named arr, which belongs to our Tester class. Therefore, arr should also consist of five values namely 0, 1, 2, 3, and 4. Now, we multiply the current values of the array arr by 10 and store them back in the same array position. This should change the values of the array arr to 0, 10, 20, 30, and 40.

Now, we again call the displayData () method on the example object. This is expected to print the values of the innerData array members. To reiterate, this array is private to example object. Therefore, it cannot be accessed from within the Tester class directly. But when called via the example object, it can be perfectly accessed, and therefore, we should get the values of the array members displayed. What should get displayed here? We expect that the array should display 0, 1, 2, 3, and 4. After all, these were the values to which the array members initialized. But to our great surprise, the output produced is 0, 10, 20, 30, and 40! Why do things work in this way?

Recall the point that arrays are objects. And we know that all objects passed to or returned from method calls are treated as references. So, when we alter the values of the members of the local array arr in our Tester class, we still have the reference to the innerData array of the example object. Hence, whenever we manipulate the values of the array arr inside our Tester class, we inadvertently end up playing with the innerData array of the example object! An attacker can use this exploit cleverly.

To prevent this, we need to make a copy of the array and return the copy, not the original array!

---

AtulKahate-JavaSecurityArticleAtul
Kahate
writes about Java Security in this monthly
column on IndicThreads.com. Atul is the author of 13 books including
"Cryptography
and Network Security
".

He is currently a Project Manager at i-flex solutions limited, Pune,
India. Atul can be reached at (akahate at gmail
dot com)

---
Related

JAVA CRYPTOGRAPHY: A BIRD'S EYE VIEW

Using the Java ByteCode Verifier To Prevent Malicious Access

Sights and Sounds Of The IndicThreads.com Conference On Java Technology


  • ‘Guest’

    i just have to make sure that i don’t buy any of the books authored/co-authored by this guy!

  • ‘Guest’

    I don’t understand the whole point of this article…primitive: pass by value & instance: pass by reference. Its as simple as that. Indicthreads shudnt allow such kinda articles.

  • ‘Guest’

    complete waste of time.

  • ‘Darth Tedious’

    I think this is why C++ had const. For some reason, when Java was first devised, the rationale for enforcing "constness" was reconsidered to its disfavor.

  • linux__rulez

    The problem with objects is also only the case if we are talking about mutable objects. Immutable objects can be safely returned. For example:

    java.lang.String
    java.lang.Integer

  • ‘Guest’

    :roll

    If you really require an writeable array result, rather than a read-only object, then replace:

    public int [] getData () {
    System.out.println (‘Inside getData …’);
    return innerData;
    }

    with:

    public int [] getData () {
    System.out.println (‘Inside getData …’);
    if (innerData==null) {
    return null;
    }
    final int n = innerData.length;
    final int[] copyData = new int[n];
    System.arraycopy(innerData, 0, copyData, 0, n);
    return copyData;
    }

    This is much safer.

    Other safe approaches are use of the Visitor pattern, with value parameters, or use of a read-only lists via the Arrays and Collections classes.

    IMHO pretty basic stuff for a competent coder.

  • ‘Guest’

    As the first poster mentions, this is a nice intro article for beginners, but you are really doing a disservice to your article by calling this a ‘security hole’. Using that with the word ‘exploit’ is a bit irresponsible too, as a technical book author, you should know the difference between security holes and unintended bugs caused by passing references around.

    This is equivalent as saying it’s a security hole to pass a pointer of any kind in C.

    You should really amend this article.

  • ‘Guest’

    can you explain a clever exploit ??

    Good , good article.
    Charles

  • Rob W

    This is a good gotcha to point out for beginning Java programmers who are still struggling with pass-by-reference (all objects including arrays) vs. pass-by-value (primitives).

    It’s a stretch to say it’s a ‘security hole’, though. Can you walk through a possible exploit?

    It’s far more likely to just cause bugs, if developers don’t understand how objects work.

    You should also be clear that this applies equally to *any* object in Java (or other OO language).

    If your Example class has a private reference to Object o, that’s only ‘private’ until you pass the
    reference out to other classes, who can do what they like with it.

    Only immutable objects like Strings, or primitives (like ints or longs, because they are pass-by-value) are going to be protected in that situation.

    Thanks for the article!
    Rob W