본문 바로가기
책/이펙티브 자바

싱글톤 - 리플렉션API 공격과 방어

by jeounpar 2023. 7. 2.

싱글톤을 만드는 방식은 여러가지가 있는데 그 중 정적 팩토리 메서드를 사용하여 만드는 방법을 살펴보자.

public class SingletonTest {
	private static SingletonTest instance = new SingletonTest();

	private SingletonTest() {
		System.out.println("SingletonTest Instance Generated");
	}
	public SingletonTest getInstance() {
		if (instance == null) {
			instance = new SingletonTest();
		}
		return instance;
	}
}

SingletonTest 클래스 생성자를 외부에서 호출할 수 없도록 생성자에 private을 사용했고 getInstance 메서드에는 객체가 초기화되지 않았을 때를 대비하여 인스턴스가 null값을 가질 때 새로운 인스턴스를 생성하도록 했다.

그런데, 정말로 외부에서 SingletonTest 인스턴스를 생성하지 못할까?

정답은 '생성할 수 있다' 이다.

자바의 리플렉션API를 사용한다면 private생성자를 호출할 수 있다.

Constructor<?> constructor = SingletonTest.class.getDeclaredConstructors()[0];
constructor.setAccessible(true);
SingletonTest singletonTest = (SingletonTest) constructor.newInstance();

AccessibleObject.setAccessible 메서드를 사용하면 private 생성자를 호출할 수 있다.

 

이를 막는 방법은 생성자를 다음과 같이 수정하여 두 번째 인스턴스가 생성되려 할 때 예외를 던지게 하면 된다.

public class SingletonTest {
	private static SingletonTest instance = new SingletonTest();

	private SingletonTest() {
    		// 두번째 인스턴스 생성시 예외 던지기
		if (instance != null)
			throw new AssertionError();
		System.out.println("SingletonTest Instance Generated");
	}
	public SingletonTest getInstance() {
		if (instance == null) {
			instance = new SingletonTest();
		}
		return instance;
	}
}

외부에서 생성자 호출 시 예외가 발생하는 것을 볼 수 있다.