암호화 컬럼과 검색용 해시 컬럼을 함께 두면, 애플리케이션은 평문을 해시로 변환해 조건절에 넣습니다.
-- customer 테이블: rrn_enc(암호화), rrn_hash(검색용) 두 컬럼
SELECT id, name, rrn_enc
FROM customer
WHERE rrn_hash = ? -- 애플리케이션에서 searchHash(입력값) 전달String hash = crypto.searchHash(inputRrn);
List<Customer> found = customerMapper.findByRrnHash(hash);
// found 의 rrn_enc 는 TypeHandler 가 자동으로 복호화한다목록 화면은 마스킹된 값만 필요하므로, 목록 조회 쿼리는 애초에 암호화 컬럼을 건드리지 않고 별도의 마스킹 컬럼이나 애플리케이션 단 마스킹을 씁니다.
public String maskedForList(String encToken) {
// 목록 화면용: 복호화 후 즉시 마스킹, 평문 보유 시간 최소화
String plain = crypto.decrypt(encToken);
return Crypto.mask(plain);
}AES-256-GCM 은 대부분의 CPU 가 AES-NI 명령어를 지원해 매우 빠릅니다. 짧은 문자열(주민번호·계좌번호 수준) 기준으로 참고할 수치를 정리합니다.
| 연산 | 대략적인 처리량 | 비고 |
|---|---|---|
| AES-GCM 암호화 | 초당 수십만 건 이상 | AES-NI 지원 CPU 기준 |
| HMAC-SHA256 | 초당 수십만 건 이상 | 암호화보다 가벼움 |
| PBKDF2(비밀번호) | 초당 수십~수백 건 | 의도적으로 느림, 인증 01 참조 |
암호화 자체는 병목이 되는 경우가 드뭅니다. 실무에서 느려지는 지점은 대개 키를 매번 KMS 에 요청하는 네트워크 왕복이므로, 키는 애플리케이션 시작 시 로드해 메모리에 캐시해 둡니다.