Closed zpqmdh closed 3 months ago
readObject와 readResolve 메서드와 finalizer 공격이 어떻게 수행되는지 명확히 이해가 가지 않습니다. 본문에서 해당 경우를 단호하게 있어서는 안 된다고 한 이유가 체감이 되지 않아 질문합니다.
readObject()
및 readResolve()
는 직렬화된 데이터파일을 읽으면서 객체 생성을 진행하는 메서드입니다.
다음의 코드를 봅시다.
class Parent {
Integer value = 0;
Parent(int value) {
// 3.
if (value <= 0) {
throw new IllegalArgumentException("value must positive");
}
this.value = value;
}
}
public class FinalizeAttack extends Parent {
static Parent parent;
FinalizeAttack(int value) {
// 2.
super(value);
}
@Override
public void finalize() {
// 6.
parent = this;
}
public static void main(String[] args) {
try {
// 1.
new FinalizeAttack(-1);
} catch (Exception e) {
// 4.
System.out.println(e);
}
// 5.
System.gc();
System.runFinalization();
// 7.
if (parent != null) {
System.out.println("attack successful parent value : " + parent.value);
}
}
}
new FinalizeAttack(-1)
로 FinalizeAttack
객체를 생성합니다.FinalizeAttack
생성자는 super(-1)
로 FinalizeAttack
의 부모 Parent
객체를 먼저 생성하는 것을 시도합니다.Parent
생성자에서 value
가 -1이기 때문에 IllegalArgumentException
이 throw
됩니다.throw
된 IllegalArgumentException
이 catch
에 잡힙니다. 해당 예외가 출력됩니다.finalize()
를 실행시킵니다.finalize()
가 실행되면서, parent
에 this
(생성되다 만 FinalizerAttack
객체)가 들어갑니다.parent
에 불완전한 FinalizerAttack
객체가 들어감으로서 parent
는 null
이 아니게 됩니다. 따라서 조건문을 만족하며 생성된 FinalizerAttack
객체의 value
값이 출력됩니다.결과는 아래 이미지와 같습니다.
Parent
생성자에서 IllegalArgumentException
을 throw
했음에도 불구하고 value
가 출력이 가능한 이유는 생성자에서 값이 초기화 되기 이전에 value
가 0으로 초기화가 진행되어서 입니다.
value
는 0으로 초기화 된 뒤, -1로 초기화되는 과정에서 Exception이 발생해 추가적인 초기화가 발생되지 않은 상태로 생성된 것을 확인할 수 있습니다.또한 예외가 발생함으로 인해 불완전하게 생성된 객체가 GC에 의해 회수되어야 함에도 불구하고, finalize()
에서 불완전한 객체를 할당함으로서 GC는 해당 객체를 회수할 수 없습니다.
또한 이미 생성된 불완전한 객체를 이용하여 해당 객체의 메서드를 제어할 수도 있습니다. 이것을 Finalizer Attack이라고 책에서 설명하고 있습니다.
readObject()
또는 readResolve()
메서드는 직렬화된 데이터파일을 읽어 객체를 만드는 동작을 수행하므로 충분히 위와 같은 Finalizer Attack에 활용될 수 있습니다. 따라서 이런 일을 예방해야 하는 경우, finalize()
메서드를 final
로 만든 뒤 아무 동작도 수행하지 않게 구현해야 합니다.
와,, !!! 너무 이해하기 쉬운 예시랑 설명을 들어주셔서 감사합니다. 덕분에 finalize attack이 왜 위험한지 느낌이 확 오네요
아이템 8 42페이지에 따르면
readObject와 readResolve 메서드와 finalizer 공격이 어떻게 수행되는지 명확히 이해가 가지 않습니다. 본문에서 해당 경우를 단호하게 있어서는 안 된다고 한 이유가 체감이 되지 않아 질문합니다.