Using the Java ByteCode Verifier To Prevent Malicious Access
Nothing’s 100% secure in computer technology. Since several years,
attackers have attempted to break into computer systems, with or
without malicious intent. On the other hand, security experts have
tried to foil attacks by using various technologies.
With this background, when Java programming was being developed, a
lot of focus was on ensuring that this new language should not have any
security holes. It was important because it was then touted as the
language of the Internet. The Internet being an open network,
accessible to everyone, any flaws in Java could directly compromise
trusted servers, internal networks and the always vulnerable clients.
Therefore, a lot of stress was put on ensuring that Java should be as
safe to use, as possible.
Moreover, attackers had found several problems in the usage of C and
C++. These languages were so powerful on one hand, but so vulnerable on the
other, because of the concept of pointers. Naturally, Java simply could
not be expected to support the concept of pointers, thereby
automatically getting rid of a lot of problems found in C and C++. However,
this was not enough.
not be expected to support the concept of pointers…
Java security designers spent considerable time in devising what is
considered as a strong security model, which focuses on the following
key factors:
- Accessibility
- Serialization
- Packages
- Privileged Code
- Native Methods
We shall now discuss these concepts in reasonable depth to understand
their context and significance, in this series of articles. This time,
we shall focus on the concept of accessibility.
By far, the simplest concept to understand is that of accessibility. We
know that the Java programming language allows the developer to define
access specifiers, that decide what level of accessibility methods,
classes, and data members can have. Java defines four levels of
accessibility, as follows:
- Public – This is the
least secure approach, where any class can access the entity defined as
public. - Protected – Mainly used
in inheritance, an entity defined as protected is accessible to the
class itself, or its subclasses, or to any classes that belong to the
same package. - Package-private –
Whenever no explicit access specifier is mentioned, this definition
takes over, and allows the class itself, and any other classes in the
same package to access the defined entity. - Private – This is the
opposite end of public, and allows only the class itself to allow an
access to this entity.
The accessibility features do not end here. In other programming
languages such as C++, the effect of access specifiers is checked at
the compile time, but not at the run time. Thus, an attacker can write
code to access private data members belonging to another class.
However, this is carefully prevented in Java. At run time, the Java
bytecode verifier ensures that the access specifiers are not violated.
Page 1 OF 2In other words, it ensures that a class can access only the entities
that it should be allowed to access. It should be pointed out that
chances of malicious code attempting to violate access specifiers are
more on the client side. Therefore, the bytecode verifier is turned on
by default when executing Java code as applets inside browsers
(client). However, this is made optional in Java applications, whereby
we can use a switch called as -verify that turns the verification on.
that the access specifiers are not violated…
It is quite interesting to know that even many experts of the Java
programming language are not aware of a possible hole in the Java
security model with reference to accessibility. We shall demonstrate
this with a simple example.
Let us first create two simple Java classes named Sufferer and
Attacker. They are shown below.
public class Sufferer {
public String test;
public Sufferer () {
test = "I am attacked!";
}
}
public class Attacker {
public static void main (String[] args) {
Sufferer sufferer = new Sufferer ();
System.out.println (sufferer.test);
}
}
Now let us compile both the classes:
C:> javac Sufferer.java Attacker.java
Let us run the example:
C:> java Attacker
The example would run with no problems, producing the output I am
attacked! This is quite normal. However, what we shall do next is quite
interesting. Let us change the access modifier in the Sufferer class
from public to private. The modified class looks as follows.
public class Sufferer {
private String test;
public Sufferer () {
test = "I am attacked!";
}
}
Let us recompile just Sufferer, but not Attacker:
C:> javac Sufferer.java
Let us rerun the example:
C:> java Attacker
What do you think will happen? We should get an error that the Attacker
class cannot access the private data member test of the Sufferer class.
But the example actually runs fine! It produces the same output as
before! This is something that most experts also find it hard to
believe.
also find it hard to
believe…
Why does this happen? It is the responsibility of the bytecode
verifier to decide if a class attempts to access controlled/restricted
entities. By default, the bytecode loaded from the file system is not
verified. We need to explicitly ask the bytecode verifier to come into
action.
The Java bytecode verifier comes to the rescue, if we use the -verify
switch. We can now rerun the example as follows:
C:> java -verify Attacker
Now the bytecode verifier comes into action at run time, and stops the
Attacker class from trying to access the private data member named test
of the Sufferer class. We get the following run time exception:
Exception in thread “main” java.lang.IllegalAccessError: tried to
access field Sufferer.test from class Attacker at
Attacker.main(Attacker.java:5)
applications with the
Sir, can you clean remove both the class files first
then change in Sufferer.java, public to private variable, and then compile again.
Even if you have Sufferer.class which has private variable, then change in Sufferer.java as public and compile Attacker.java its working.. why?
If -verify helps protect private variables why is it not enabled by default? Are there any drawbacks?
Looks like a security hole is kept open unnecessarily 😕