|
Page 2 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!
---
Atul
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
|
Comment by Rob W on 2007-03-14 22:26:19 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 | Comment by 'Guest' on 2007-03-19 09:26:05 can you explain a clever exploit ?? Good , good article. Charles | Comment by 'Guest' on 2007-03-21 13:06:29 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. | Comment by 'Guest' on 2007-03-21 14:37:52 :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. | Comment by linux__rulez on 2007-03-22 07:41:03 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 | Comment by 'Darth Tedious' on 2007-03-22 11:30:47 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. | Comment by 'Guest' on 2007-04-23 03:18:00 complete waste of time. | Comment by 'Guest' on 2007-04-30 14:50:57 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. | Comment by 'Guest' on 2007-04-30 14:58:14 i just have to make sure that i don't buy any of the books authored/co-authored by this guy! |
|