Re: Frequently Asked Questions - Applet Security

Radu Nicolescu (radu@lara.tcs.auckland.ac.nz)
Mon, 26 May 97 17:23:00 +1200

Message-Id: <9705260523.AA02009@lara.tcs.auckland.ac.nz>
From: Radu Nicolescu <radu@lara.tcs.auckland.ac.nz>
Date: Mon, 26 May 97 17:23:00 +1200
To: java-security@web2.javasoft.com
Subject: Re: Frequently Asked Questions - Applet Security

Hi,

This is not exactly a question about applet security. It may be a
bug, but it may also be a feature of which I am not aware. It is
perhaps related to binary compatibility. Strange enough, many texts
(including a presentation by Gosling) seem to insist that there is
no way in Java to access private variables from outside their class,
and talk about ugly things such as pointer arithmetic, etc.

Well, perhaps I am wrong in some ways, but here is my story, for
you to judge (I am only a beginner in Java).

SOAPBOX: How private is private?
================================

Introduction
------------

Many OO texts talk about private fields as entities which are
hardly accessible to mortal users, and guaranteed inaccessible in
Java. Is it indeed the case if you consider complex programs
consisting of more than one source file? Would you put
confidential, sensitive information in a private field of a software
object, even in the case of Java?

I think that there is a surprisingly straightforward backdoor which
allows easy access to private Java fields (but which may not be
always open, eg., it is not open for downloaded applets). The method
is so natural that probably is widely known, altough I have only
recently appreciated its full glory. Who knows more about this? Any
comments would be much appreciated.

1. OO Misconceptions
--------------------

1.1 You can't access private fields of another class.

1.2 You need pointer arithmetic and unsafe casting to access
private fields.

2. Solutions
------------

Forget about ugly pointer arithmetic and unsafe casting. Next are
some more decent solutions.

2.1 C++
-------

Prefix all your source files with the following two lines (before
your #include's):

#define private public
#define protected public

That should work in most cases, but the cure is too brutal (removes
privacy from all objects).

2.1 Objective-C
---------------

You have language support for precise surgery. There is a compiler
directive called @defs(), which basically casts a given object into
a traditional C structure (with all protection removed).

2.3 Java
--------

2.3.1 Consider the following files (both in the same folder):

// File Random.java
public class Random {
public long seed;
}

// File RandomTest.java
public class RandomTest {
public static void main( String arg[] ) {
Random r = new Random();
System.out.println( r.seed );
}
}

Proceed as follows:

i) Compile Random.java:

javac Random.java

ii) Compile RandomTest.java:

javac RandomTest.java

You can now test run RandomTest:

java RandomTest

This prints the value of the public ivar r.seed, where r is an
instance of our Random class.

iii) Change the source Random.java by replacing "public long seed"
with "private long seed" and recompile it.

iv) Run again RandomTest. This prints now the value of the private
ivar r.seed!, where r is an instance of our new Random class.

2.3.2 The previous experiment was a bit strange, but not very
spectacular. However, we can spice it. We prefix each source file
with one more line, so they now read:

// File Random.java
package java.util;
public class Random {
public long seed;
}

// File RandomTest.java
import java.util.Random;
public class RandomTest {
public static void main( String arg[] ) {
Random r = new Random();
System.out.println( r.seed );
}
}

We proceed now as follows:

i) Compile Random.java by putting the compiled class in local
package called java.util:

javac -d . Random.java

This will create a local subfolder called java, containing a
subfolder called util, containing the bytecode for Random.

ii) Compile RandomTest.java:

javac RandomTest.java

The compiler uses the local Random, not the standard one.

You can now test run RandomTest:

java RandomTest

The runtime uses the local Random, so this prints the value of the
public ivar r.seed, where r is an instance of our local Random, ie.
0 in our case.

iii) Delete or rename the local java/util/Random.class (to make it
inaccessible).

iv) Run again RandomTest; the runtime uses now the standard
java.util.Random class. This prints the value of the private ivar
r.seed!, where r is now an instance of the standard java.util.Random
class!, ie, 880296719516!

NB1: This seems to work well with apps and local applets, but not
with applets downloaded over the net.

NB2: These results were obtained with JDK 1.0.2 running on Windows
95 and Solaris, so I presume that they can be obtained with any
conformant JDK kit.

Conclusion
----------

As ever known, the access modifiers (private/protected/public) may
protect against accidental misuse, but against little else. They may
not offer adequate protection against intentional misuse, despite
claims to the contrary.

????

Radu

-------------------------------------------------
Dr Radu Nicolescu
The University of Auckland
Tamaki Campus, Division of Science and Technology
Private Bag 92019, Auckland, New Zealand
Tel: 0064-9-373 7599 x6831
Fax: 0064-9-373 7001
Email: r.nicolescu@auckland.ac.nz
-------------------------------------------------