javasecuritystatic-analysisfortify

How exactly can someone without source code access exploit a non-final class that has a constructor which invokes overridable functions?


I'm trying to understand how exactly can someone that doesn't already have access to the source code exploit a non-final class that has a constructor which invokes overridable functions (functions not marked final).

This question comes from the fact that after scanning my source code with a Source Code Analyzer (Fortify), it showed a few findings about "Code Correctness: Constructor Invokes Overridable Function".

Some of the references for the issue, or bad practice, are:

  1. Guideline 4-5 / EXTEND-5: Limit the extensibility of classes and methods (link)
  2. Guideline 7-4 / OBJECT-4: Prevent constructors from calling methods that can be overridden (link)

I understand why the code is being flagged and I also understand how I can mitigate/remove the finding. But I'd like to understand how someone could actually exploit this unless they have access to the source code. Since in that case, they could really just wreak havoc and wouldn't care much about this triviality. Surely I am missing something!


Solution

  • You do not need source code to extend a class and overwrite some methods - you only need the corresponding .class file for that.

    Suppose you would do something dumb like

    public class PayFlowjoe {
      public PayFlowjoe() {
        sendMoneyTo(getRecipient());
      }
    
      protected String getRecipient() {
        return "flowjoe";
      }
    
      private void sendMoneyTo(String recipient) {
        System.out.println("Sending money to " + recipient);
      }
    }
    

    then I could create a class

    public class PayMe extends PayFlowjoe {
      protected String getRecipient() {
        return "me";
      }
    }
    

    and creating an instance of PayMe would send money to me instead of you. To compile PayMe, you only need the PayFlowjoe.class file. To create an instance of PayMe and trigger the bad code, you simply need to put PayFlowjoe.class in the classpath of the application that uses PayMe.

    By the way - it is actually fairly easy to use a decompiler to get the PayFlowjoe source code from the PayFlowjoe.class file.