A non-final class or method, which is not meant to be inherited, can be overridden by an attacker, if it is not declared as final [3].
In case inheritance is to be limited to trusted implementations for a public, non-final class, then the class type should be confirmed before creating the instance at each place where an instance of the non-final class can be created. A SecurityManager check should be enforced on detecting a subclass (Chapter 6 of [2]).
A non-final class can be subverted simply by declaring a malicious class that inherits from the non-final class which implies that there is no need for reflection. However, reflection is necessary if the non-final class is private or otherwise inaccessible to the attacker.
Non Compliant code example:
In this code, an attacker can easily create an instance and override methods of BankOperation
.
class BankOperation{ //the account balance has already been retrieved from the database and stored in the foll variable private Integer balance = 5000; public BankOperation() { //invoke java.lang.Object.getClass to get class instance Class clazz = getClass(); //shows the class of the instantiated object System.out.println(clazz); } public void getBalance() { System.out.println("The current balance is: $" + balance); } } //this class has been written by the attacker public class SubClass extends BankOperation { public void getBalance() { //The attacker can change his account balance to any value he wants. Integer modifiedBalance = 0; //to read the new balance from the attacker InputStreamReader input = new InputStreamReader(System.in); Field balance=null; BufferedReader reader = new BufferedReader(input); System.out.print("Enter balance: "); try { modifiedBalance = Integer.parseInt(reader.readLine()); //this gets the private field from the superclass balance = this.getClass().getSuperclass().getDeclaredField("balance"); //this changes the accessibility so that field can now be accessed if (!Modifier.isPublic(balance.getModifiers())){ balance.setAccessible(true); } //retrieve the original balance System.out.println("Original Balance: $"+balance.get(this)); //change the balance balance.set(this, modifiedBalance); //display the new changed balance System.out.println("New Balance: $"+balance.get(this)); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { SubClass subclass = new SubClass(); subclass.getBalance(); } }
Compliant Solution:
This compliant solution can be achieved by using the keyword final, thus ensuring that the sensitive class cannot be extended.
final class BankOperation{ //normal coding... }
In case the class needs to be extended, then permissions should be checked in case a sub class is detected during construction so that malicious implementations are blocked.
Risk Assessment:
Allowing a non-final class or method to be inherited without checking the class instances, allows an attacker to exploit it.
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
OBJ33-J |
high |
probable |
high |
P3 |
L3 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website
Reference:
SCG 07 Secure Coding Guidelines for the Java Programming Language