6

In Effective Java (Chapter 7), it says

Note also that we did not use Date’s clone method to make the defensive copies. Because Date is nonfinal, the clone method is not guaranteed to return an object whose class is java.util.Date: it could return an instance of an untrusted subclass specifically designed for malicious mischief. Such a subclass could, for example, record a reference to each instance in a private static list at the time of its creation and allow the attacker to access this list. This would give the attacker free reign over all instances. To prevent this sort of attack, do not use the clone method to make a defensive copy of a parameter whose type is subclassable by untrusted parties.

I don't quite understand its explanation. Why does clone() not return a Date object? How can the instance be of untrusted subclass?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Kyle
  • 379
  • 6
  • 17

4 Answers4

5

clone() is widely regarded to have been a failed experiment for a number of reasons. In this case, someone passing in a Date could have passed in an EvilDate extends Date whose clone() method sneakily returned a copy that was still mutable by someone else.

chrylis -cautiouslyoptimistic-
  • 75,269
  • 21
  • 115
  • 152
5

Consider this code:

public class MaliciousDate extends Date { /** malicious code here **/ }

public class SomeClass {
    public static void main(String[] args) {
        MaliciousDate someDate = new MaliciousDate();
        Date copyOfMaliciousDate = someDate;
        Date anotherDate = copyOfMaliciousDate.clone();
    }
}

Since copyOfMaliciousDate is of type Date, you can call clone() and it will return a Date object, but calling clone on copyOfMaliciousDate executes the code written in the MaliciousDate class' clone() because the instance stored in copyOfMaliciousDate is a MaliciousDate.

Leponzo
  • 624
  • 1
  • 8
  • 20
egracer
  • 362
  • 3
  • 10
  • 1
    Obviously, but why is that a concern for `clone()` only? If you do not trust that implementations will adhere to method contracts or even you suspect they would be outright malicious, you should not trust _any_ overridden method. Which effectively kill polymorphism and OOP to begin with. I am probably missing something. – Oliver Gondža Oct 25 '17 at 08:42
  • Haven't read the book myself so I'm not sure of the full context, just took the assumptions made by the passage that accompanied the question. If I had to guess, I'd say that the passage refers to a library that you are implementing for consumption by a third party. Don't use `clone()` for defensive copying unless your class is a final class. – egracer Oct 26 '17 at 00:09
2

I haven't read the book you quoted from, but that paragraph gives a poor justification and offers no protection against any sort of attack.

The quote mentions that an attacker with the ability to load code into your program could potentially submit a Date subclass with malicious methods, for example returning a subclass of Date from clone.

But that's only a minor way an attacker with the ability to load code can cause harm. They could also:

  • Use reflection to get read+write access to pretty much anything marked private,
  • Mess with the class loaders to load their own versions of classes,
  • Call System.exit() to stop your program, and
  • Do anything your program could do, like spawn other programs or access files.

If the attacker is running code in your process, the game's over and your process is compromised, and this silly little guard is not going to help.

Maybe you think that clone is bad from a design standpoint, and that's fine, but please don't pretend that not using it will protect you from some security threat, because it won't.

Colonel Thirty Two
  • 23,953
  • 8
  • 45
  • 85
  • This is the BEST and correct answer. The text from the book gives the idea that not using clone will somehow help with the application security. But if the attacker can simply inject a class in the classpath, that it all he needs to do whatever he wants! Congrats for the answer, straight to the point! – Rodrigo V May 13 '23 at 07:37
0

Since Date class is non-final, it can be extended and the clone method can be overridden to store the instances which later can be accessed to modify the state.

MaliciousDate.java

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class MaliciousDate extends Date {

    private static List<MaliciousDate> instances = new ArrayList<>();

    @Override
    public Object clone() {
        instances.add(this);
        return super.clone();
    }

    public List<MaliciousDate> getInstances() {
        return instances;
    }
}

Period.java

import java.util.Date;

public class Period {
    private static Date start;
    private static Date end;

    public Period(Date start, Date end) {
        this.start = (Date) start.clone();
        this.end = (Date) end.clone();
        if (start.getTime() > end.getTime()) {
            throw new IllegalArgumentException("start is greater than end");
        }
    }

    public static void main(String[] args) {
        MaliciousDate start = new MaliciousDate();
        MaliciousDate end = new MaliciousDate();
        Period p = new Period(start, end);
        //...
    }

}
  • Could you clarify what is wrong in the example shared. – Akin Okegbile Feb 13 '23 at 18:53
  • 1
    Nothing seems incorrect to me. This answer would further support the passage from the book.`Such a subclass could, for example, record a reference to each instance in a private static list at the time of its creation and allow the attacker to access this list. This would give the attacker free reign over all instances.` – Abipriya Rajendran Feb 15 '23 at 03:58