Access control
Table of contents
- Access control
- Classes access modifiers table
- Class members access modifiers table
- Which access modifier should I pick?
Access control
We know that the Random class produces a pseudo random sequence. This means that a skilled attacker can predict the next number to be drawn after making several observations.
Consider the following example.
package demo;
import java.util.Random;
public class Dice {
  public static int roll() {
   return RANDOM_GENERATOR.nextInt( 6 ) + 1;
  }
  public static final Random RANDOM_GENERATOR = new Random(1);
}
The above example makes use of static fields to highlight other problems that may be created when having fields marked as static.
The Random object is initialised with a seed to simplify the example. Both the roll() method and the random static field can be accessed from anywhere. An attacker can take advantage of that and force the next dice roll to be a 6.
Consider the following example.
package demo;
public class App {
  public static void main( final String[] args ) {
   /* This method is hacked by an attacker */
   initGame();
   /* This will always roll a 6 */
   playGame();
  }
  public static void playGame() {
   final int a = Dice.roll();
   System.out.printf( "I rolled a %s%n", a );
  }
  public static void initGame() {
   /* Skip some numbers so that the next roll, rolls a 6 */
   for ( int i = 0; i < 19; i++ ) {
     Dice.RANDOM_GENERATOR.nextInt();
   }
  }
}
Observations
- The attacker first called the - nextInt()method- 19times.- for ( int i = 0; i < 19; i++ ) { Dice.random.nextInt(); }- The attacker knows that the 20th roll will yield a - 6.
- The attacker then rolled the dice normally - final int a = Dice.roll(); System.out.printf( "I rolled a %s%n", a );- and obtained the expected the attacker wanted. - I rolled a 6- The attacker can also skip ahead some numbers to make the opponent lose, by rolling a smaller number. 
- The - Diceclass uses static fields on purpose. Only one instance of the- staticfield- RANDOM_GENERATORexists and anyone can access it from anywhere in the code.
Using access modifies, access to classes and their members (properties, static fields and methods) can be restricted. Making the static field random, private, will not allow an attacker to access the static field directly.
package demo;
import java.util.Random;
public class Dice {
  public static int roll() {
   return RANDOM_GENERATOR.nextInt( 6 ) + 1;
  }
  private static final Random RANDOM_GENERATOR = new Random( 1 );
}
The attacker cannot now access the random field.
package demo;
public class App {
  public static void main( final String[] args ) {
   /* This method is hacked by an attacker */
   initGame();
   /* This will always roll a 6 */
   playGame();
  }
  public static void playGame() {
   final int a = Dice.roll();
   System.out.printf( "I rolled a %s%n", a );
  }
  public static void initGame() {
   /* Skip some numbers */
   for ( int i = 0; i < 19; i++ ) {
     /* ⚠️ Cannot access the private field!! */
     Dice.RANDOM_GENERATOR.nextInt();
   }
  }
}
The following error will be produced
src/main/java/demo/App.java:21: error: RANDOM_GENERATOR has private access in Dice
     Dice.RANDOM_GENERATOR.nextInt();
         ^
Classes access modifiers table
| Access Modifier | Accessible From | 
|---|---|
| public | Anywhere | 
| (no modifier) | same package | 
Note that inner classes are class members and thus do not make use of the above table. Inner classes use the table shown in the following section.
Class members access modifiers table
| Access Modifier | From Same Class | From Same Package | From Subclass | From Anywhere | 
|---|---|---|---|---|
| public | Yes | Yes | Yes | Yes | 
| protected | Yes | Yes | Yes | No | 
| (no modifier) | Yes | Yes | No | No | 
| private | Yes | No | No | No | 
Note that there can be more than one class within the same file. Two or more classes in the same file are considered as classes in the same package.
package demo;
public class A {
  public static void printIt() {
   System.out.printf( "The value of c is %d%n", B.c );
  }
}
class B {
  private static final int c = 7;
}
Both classes are defined in the same source file, A.java, yet these are two different classes within the same package.
$ tree build/classes/java
build/classes/java
└── main
    └── demo
        ├── A.class
        └── B.class
There is one exception to this rule. Consider the following example.
package demo;
public class App {
  private static final int c = 7;
  public static void main( final String[] args ) {
   final Runnable r = new Runnable() {
     @Override
     public void run() {
       System.out.printf( "The value of c is %d%n", c );
     }
   };
   r.run();
  }
}
An inner anonymous class is created within the App class.
final Runnable r = new Runnable() {
  @Override
  public void run() {
   System.out.printf( "The value of c is %d%n", c );
  }
};
This is compiled as a separate class file, App$1.class.
$ tree build/classes/java
build/classes/java
└── main
    └── demo
        ├── App$1.class
        └── App.class
Despite being a different class within the same package, the inner anonymous class is still allowed to access private members within the parent class.
More information about access control can be found in this tutorial.
Which access modifier should I pick?
Always start with the least visible access modifier, private, and then increase the visibility only if required. Remember that once you make something public it may be impossible to reduce its visibility.