JPA/Hibernate 미드레벨 보안 면접
새 면접Q. JPA를 사용할 때 SQL 인젝션 공격을 방어할 수 있는 방법들을 설명하고, JPQL이나 Native Query를 작성할 때 주의해야 할 보안 사항은 무엇인가요?
파라미터 바인딩 방식의 차이와 동적 쿼리 생성 시 주의점을 고려해보세요.
JPA에서는 Prepared Statement를 기반으로 하는 파라미터 바인딩을 사용하여 SQL 인젝션을 방어합니다. JPQL이나 Criteria API를 사용할 때는 setParameter() 메서드로 파라미터를 바인딩하면 자동으로 이스케이핑이 처리됩니다. 반면 Native Query에서 문자열 연결로 쿼리를 동적 생성하거나, createQuery()에 직접 변수를 포함시키면 SQL 인젝션에 취약해집니다. 특히 @Query 어노테이션에서 SpEL을 사용하거나, 정렬 컬럼명처럼 바인딩할 수 없는 부분은 화이트리스트 방식으로 검증해야 합니다. 동적 쿼리가 필요한 경우 Criteria API나 QueryDSL 같은 타입 세이프한 방식을 사용하는 것이 안전합니다.
- • 파라미터 바인딩(setParameter)을 통한 Prepared Statement 사용
- • 문자열 연결로 쿼리 생성 시 SQL 인젝션 위험
- • 정렬/테이블명 등 바인딩 불가 영역은 화이트리스트 검증 필요
사용자 입력을 기반으로 검색 필터나 정렬 기능을 구현할 때 SQL 인젝션 방어가 필수적입니다.
Sort 객체를 사용한 동적 정렬에서 악의적인 컬럼명이 입력될 경우 어떻게 방어할 수 있을까요?
Q. JPA 엔티티에 주민등록번호, 신용카드 번호 같은 민감정보를 저장해야 할 때, 암호화 처리를 위한 설계 방법과 성능 최적화 전략을 설명해주세요. 특히 검색 요구사항이 있을 때의 트레이드오프는 무엇인가요?
AttributeConverter를 활용한 투명한 암호화와 인덱싱 문제, 그리고 해시를 활용한 검색 전략을 생각해보세요.
JPA의 AttributeConverter를 구현하여 엔티티 필드의 암호화/복호화를 투명하게 처리할 수 있습니다. AES-256 같은 대칭키 암호화를 사용하며, 키는 환경변수나 KMS에서 관리합니다. 하지만 암호화된 컬럼은 인덱스가 무의미하므로 검색 성능이 저하됩니다. 이를 해결하기 위해 검색용 해시 컬럼을 별도로 두는 방법이 있는데, 원본 데이터를 SHA-256으로 해시하여 저장하고 검색 시 입력값의 해시로 비교합니다. 성능 최적화를 위해서는 자주 조회되는 데이터는 애플리케이션 레벨에서 캐싱하되, 캐시에는 복호화된 데이터를 저장하지 않도록 주의해야 합니다. 또한 JPA의 2차 캐시를 사용할 때는 암호화된 상태로 캐싱되도록 설계해야 하며, 감사 로그에도 민감정보가 평문으로 남지 않도록 @PrePersist, @PreUpdate 리스너를 활용합니다.
- • AttributeConverter로 투명한 암호화/복호화 처리
- • 검색용 해시 컬럼 별도 관리로 성능과 보안 균형
- • 캐시와 로그에서 민감정보 노출 방지
금융, 의료, 전자상거래 시스템에서 개인정보 보호법 준수를 위해 민감정보 암호화와 검색 기능을 동시에 구현해야 합니다.
GDPR의 잊혀질 권리를 구현할 때, JPA의 Soft Delete와 물리적 삭제 중 어떤 방식을 선택해야 하며 그 이유는 무엇인가요?
Q. 멀티테넌트 SaaS 애플리케이션에서 각 테넌트의 데이터를 격리해야 합니다. JPA/Hibernate를 사용할 때 데이터 접근을 제어하고, 실수로 다른 테넌트의 데이터에 접근하는 것을 방지하는 설계 패턴과 구현 방법을 설명해주세요.
Hibernate의 필터 기능과 스프링 시큐리티의 컨텍스트를 조합하는 방법을 고려해보세요.
Hibernate의 @FilterDef와 @Filter 어노테이션을 사용하여 전역적으로 테넌트 필터를 적용할 수 있습니다. 모든 엔티티에 tenantId 컬럼을 추가하고, @Filter로 현재 테넌트의 데이터만 조회되도록 제한합니다. 필터 활성화는 스프링 인터셉터나 AOP에서 SecurityContextHolder의 인증 정보를 기반으로 session.enableFilter()를 호출하여 처리합니다. 추가로 @PrePersist, @PreUpdate 리스너에서 엔티티 저장 시 자동으로 현재 테�ान트ID를 주입하여 개발자 실수를 방지합니다. Native Query 사용 시에는 필터가 적용되지 않으므로, 반드시 WHERE 절에 테넌트 조건을 명시해야 하며, 코드 리뷰에서 이를 체크하는 정책이 필요합니다. 더 강력한 격리가 필요하면 Hibernate의 멀티테넌시 기능으로 스키마나 데이터베이스를 분리하는 방법도 고려할 수 있습니다.
- • Hibernate @Filter로 전역 테넌트 필터 적용
- • 엔티티 리스너로 저장 시 자동 tenantId 주입
- • Native Query에서는 필터가 동작하지 않으므로 별도 검증 필요
B2B SaaS 플랫폼에서 고객사별 데이터 격리는 필수이며, 잘못된 구현 시 심각한 데이터 유출 사고로 이어질 수 있습니다.
슈퍼 관리자가 모든 테넌트의 데이터를 조회해야 하는 경우, 필터를 선택적으로 비활성화하는 안전한 방법은 무엇인가요?
아직 댓글이 없습니다. 첫 번째 댓글을 남겨보세요!