Make everything final
Polymorphism is a building block of the Object-Oriented approach.[12] Polymorphism is the system set into place to deal with dynamically choosing the proper method for execution in languages with inheritance. In Java the public interface of a class is defined by the public methods defined within that class as well as the public interface of all of that classesÕ super classes. Polymorphism is the system that dynamically determines the objectsÕ type and what version of a particular method should be called depending upon how the method is overridden in the inheritance tree. If an object is declared as a certain super-class and then is initialized as a subclass of that super-class and the method foo() is defined in both classes it is polymorphism that will dynamically determine at run time that the sub-classesÕ version of foo() should be called. This is a dynamic system, the executed method is completely determined at runtime and there is no way for a programmer to influence this choice. A method in a super-class can be overridden in a subclass.
Overriding is the system to change the behavior of a super-classes method. To do this it is necessary to create a method in the subclass that has the exact same signature as the method in the superclass. The parameters, name and return type are identical to the method in the superclass. When this method is called on an instance of the subclass, whether or not the object was declared as the subclass or super-class, the method as defined in the subclass is called. Herein lies the vulnerability. The only requirements of the overridden method is an identical signature, the additional code executed is completely defined by the author of the subclass. Keeping the signatures the same, the author of the subclass could modify the behavior of the method and compromise the security of the class. [6]
To prevent this from happening it is possible to use the modifier ÒfinalÓ when defining variables or methods, this tags the variable or method so it cannot be overridden in a subclass. Use of this modifier eliminates many possible applications of an extended class or even the extension of the class itself. The variables and methods cannot be overridden and their behavior cannot change. Even though future programmers are restricted to your implementation, this is a very important precaution to take. When a method is not marked final then it can be overridden and the behavior and actions of the overridden method is completely out of your hands. It is possible to that the new method could execute code that compromises the security of your application.
An example of such a security bug is as follows. Let us say a method of a class is set up to check whether the passed username and password is a valid match.
Class PassCheck {
HashMap users; //set up to return password of the passed username
É
public boolean passwordCheck(String username, String password){
if(password.equals(users.get(username)))
return true;
else
return false;
}
}
To exploit the fact that the class nor the method is final a subclass could be defined as follows:
Class PassCheckToo extends PassCheck {
HashMap stolenUsernames;
É
public boolean passwordCheck( String username, String password) {
boolean isValid = super.passwordCheck(username, password);
if(isValid)
stolenUsernames.put(username, password);
return isValid;
}
}
In this example the subclass behaves just as its superclass implementation would, however it also stores the passed values in a new HashMap that the author of the subclass could access in any number of ways. This is an overly simplified example; hopefully more security precautions would be taken to secure usernames and passwords. The purpose is to highlight the fact that a method can be overridden to include malicious code without changing making any behavioral changes. Another example might include getter and setter methods that are not finalized; similar to this example, the values passed in may be stored and later analyzed by the author of the subclass. Extensibility is one of the powerful features of a language with inheritance; with as many approaches as there are programmers, classes can be extended in infinitely many novel ways. This is beneficial feature except when dealing with applications where security is a concern. Any un-finalized class or method can be extended in unseen ways and executed in other parts of your code through polymorphism. It is far easier to approach the reciprocal to this problem and finalize everything except for the few cases were it is necessary not to.