Spring 애플리케이션을 개발하다 보면 코드가 간결해지고 개발 생산성도 높일 수 있어 Lombok을 자주 사용하게 됩니다.

Lombok에서 제공하는 @ToString 어노테이션은 객체의 상태를 문자열로 쉽게 확인할 수 있어 디버깅에 유용합니다. 하지만 @ToString을 그대로 사용하면 의도하지 않게 로그에 개인정보가 기록될 수 있습니다.


1. @ToString이 생성하는 코드

@ToString은 객체의 toString() 메서드를 자동으로 생성하는 Lombok 어노테이션입니다. 별도의 옵션을 지정하지 않으면 클래스의 모든 필드를 포함하는 toString() 메서드가 생성됩니다.

예를 들어 다음과 같은 클래스가 있다고 가정해보겠습니다.

@Data
@ToString
public class Member {
    private int memberId;        // 회원 ID: 일반정보
    private String memberLevel;     // 회원등급: 일반정보
    private String phoneNumber;     // 전화번호: 개인정보
    private String email;           // 이메일주소: 개인정보
    private String ci;              // CI: 개인정보
}

컴파일 시점에 toString() 메서드가 Lombok에 의해 자동으로 생성될 것입니다. 아래 코드는 이해를 돕기 위해 단순화한 예시입니다.

@Override
public String toString() {
    return "Member(memberId=" + memberId +
           ", memberLevel=" + memberLevel +
           ", phoneNumber=" + phoneNumber +
           ", email=" + email +
           ", ci=" + ci + ")";
}

2. 무엇이 문제인가?

문제는 객체 전체를 로그로 출력하는 코드가 의도치 않게 운영 환경까지 남아있는 경우입니다. 혹시라도 개발자가 디버깅을 위해서 작성했던 로그 출력 코드가 호출되면 어떻게 될까요?

log.info("member={}", member);

위의 코드가 실행된다면 Member 객체의 toString() 메소드가 호출됩니다. 따라서 개인정보에 해당하는 휴대전화 번호, 이메일 주소, CI까지 일반 정보와 함께 모두 출력될 것입니다. 개발자는 의도하지 않았지만 로그에는 개인정보가 남게 됩니다.

member=Member(
    memberId=1000,
    memberLevel=BASIC,
    phoneNumber=01012345678,
    email=who@test.com,
    ci=ABCDEF1234567890
)

한 번 기록된 로그는 오랜 기간 보관되기도 하며, 여러 운영자가 조회할 수도 있습니다. 데이터베이스에는 암호화된 개인정보를 저장했더라도 로그에 평문으로 남아있는 개인정보가 더 큰 보안문제의 원인이 될 수 있습니다.

운영 환경에서는 예외 로그나 디버그 로그를 통해 객체 전체가 출력되는 경우가 많기 때문에 더욱 주의해야 합니다.


3. 권장 방법

개인정보가 포함된 클래스에는 @ToString을 사용하지 않는 것을 권장합니다. 필요하다면 toString()을 직접 구현하여 출력할 필드를 명시적으로 관리하는 것이 가장 안전합니다.

다만 @ToString을 사용해야 한다면 onlyExplicitlyIncluded 옵션을 사용하여 필요한 필드만 출력하도록 설정하는 것이 좋습니다.

아래는 onlyExplicitlyIncluded 옵션을 사용하는 예제 코드입니다.

@Getter @ToString(onlyExplicitlyIncluded = true) 
public class Member { 
    @ToString.Include 
    private Long memberId; 
    
    @ToString.Include 
    private String memberLevel; 

    private String phoneNumber; 
    private String email; 
    private String ci; 
}

이렇게 하면 toString() 메소드를 호출하더라도 @ToString.Include가 적용된 필드만 출력됩니다.

또한 객체 전체를 출력하기보다는 필요한 값만 로그로 남기는 습관을 권장합니다.

log.info("memberId={}, memberLevel={}",
        member.getMemberId(),
        member.getMemberLevel());

4. 마무리

@ToString은 매우 편리한 기능이지만, 개인정보가 포함된 객체에서는 예상하지 못한 정보 유출의 원인이 될 수 있습니다.

잘못 사용하면 log.info("{}", member)처럼 평범해 보이는 코드 한 줄만으로도 개인정보가 로그에 기록될 수 있습니다.

특히 운영 환경에서는 로그도 중요한 보안 자산입니다. 객체 전체를 출력하는 습관보다는 필요한 정보만 명시적으로 로그에 남기는 것이 안전한 개발 습관이라고 생각합니다.

데이터베이스에 저장되는 개인정보는 암호화에 신경 쓰는 경우가 많지만, 로그는 상대적으로 관리가 소홀해지는 경우가 있습니다. 따라서 로그에도 개인정보가 기록되지 않도록 개발 단계에서부터 주의하는 것이 중요합니다.