네이티브 메서드를 사용하지 않으니 C, C++에서 흔히 보는 버퍼 오버런, 배열 오버런, 와일드 포인터 같은 메모리 관련 오류에서 안전
하지만, 다른 클래스로부터의 침범을 아무런 노력없이 막을 수 있는건 아니다!
방어적으로 프로그래밍을 해야한다.
악의적인 의도를 가진 사람들이 시스템의 보안을 뚫을려는 시도
Period Sample
public final class Period {
private final Date start;
private final Date end;
public Period(Date start, Date end) {
if (start.compareTo(end) > 0) {
throw new IllegalArgumentException(start + " after " + end);
}
this.start = start;
this.end = end;
}
public Date start() {
return start;
}
public Date end() {
return end;
}
public void print() {
System.out.println("start : " + start);
System.out.println("end : " + end);
}
}
Period 인스턴스의 내부를 공격해보자
end의 setYear를 통해서 p의 내부 end의 값도 변경이 되어버린 상황
java8에서는 Date 대신 불변 Instant를 사용하면 된다. (LocalDateTime, ZoneDateTime)
Date는 새로운 코드를 작성할 때는 더 이상 사용하지 말것.
오래된 Date라 내부 구현에 잔재가 남아있을 가능성이 높다.
내부를 보호하려면!
생성자에서 받은 가변 매개변수 각각을 방어적으로 복사(defensive copy) 해야한다.
수정한 생성자 - 매개변수의 방어적 복사본을 만든다.
public Period(Date start, Date end) {
// Old version
// if (start.compareTo(end) > 0) {
// throw new IllegalArgumentException(start + " after " + end);
// }
// this.start = start;
// this.end = end;
this.start = new Date(start.getTime());
this.end = new Date(end.getTime());
if (this.start.compareTo(this.end) > 0) {
throw new IllegalArgumentException(this.start + " after " + this.end);
}
}
실행 결과
주목 : 매개변수의 유효성 검사(Item 49)를 하기 전에 방어적 복사본을 만들고, 이 복사본으로 유효성을 검사
멀티스레딩 환경이라면 원본 객체의 유효성을 검사한 후 복사본을 만드는 그 찰나의 취약한 순간에 다른 스레드가 원복 객체를 수정할 위험성이 존재
item 50 : 적시에 방어적 복사본을 만들라
Period
SamplePeriod
인스턴스의 내부를 공격해보자end
의setYear
를 통해서 p의 내부 end의 값도 변경이 되어버린 상황Date
대신 불변 Instant를 사용하면 된다. (LocalDateTime
,ZoneDateTime
)Date
는 새로운 코드를 작성할 때는 더 이상 사용하지 말것.Date
라 내부 구현에 잔재가 남아있을 가능성이 높다.수정한 생성자 - 매개변수의 방어적 복사본을 만든다.
Date
의clone
을 사용하지 않았다.clone
이 악의를 가진 하위 클래스의 인스턴스를 반환할 가능성이 있음clone
을 사용하지 말것.Period
인스턴스를 향한 두번째 공격public Date end() { return new Date(end.getTime()); }