포스트

DB에 저장하는 민감정보를 암호화하기

저장 시 암호화(encryption at rest)가 검색·정렬 가능성과 어떻게 충돌하는지, 키 관리와 블라인드 인덱스로 그 충돌을 푸는 법을 다룬다.

DB에 저장하는 민감정보를 암호화하기

민감정보 저장을 다룬 주였다. 주민번호, 계좌, 전화번호 같은 개인식별정보(PII)는 평문으로 DB에 두면 한 번의 유출로 끝장이다. 그래서 암호화해 저장한다. 그런데 암호화하는 순간, 우리가 당연하게 쓰던 “이 번호로 검색”이 통째로 막힌다. 이 충돌을 이해하는 것이 이 작업의 핵심이다.

저장 시 암호화(at-rest)의 원리

저장 시 암호화는 애플리케이션이 값을 DB에 넣기 전에 암호문으로 바꾸고, 읽을 때 복호화하는 방식이다. AES 같은 대칭키 알고리즘을 쓰며, 좋은 암호화는 같은 평문이라도 매번 다른 암호문을 만든다 — 매 암호화마다 무작위 IV(초기화 벡터)를 섞기 때문이다. 이것이 보안의 핵심이다. 패턴 분석으로 “이 두 사람은 같은 번호다”를 추론하지 못하게 한다.

1
2
3
// 같은 평문 → 매번 다른 암호문 (랜덤 IV 때문)
String c1 = encryptor.encrypt("010-1234-5678"); // "iv1:....."
String c2 = encryptor.encrypt("010-1234-5678"); // "iv2:....." (c1과 다름)

왜 검색이 불가능해지는가

바로 이 “매번 다른 암호문” 성질이 검색을 죽인다. DB에는 c1이 저장돼 있는데, 검색하려고 같은 번호를 다시 암호화하면 c2가 나온다. WHERE phone_enc = 'c2'는 절대 매치되지 않는다. 정렬도 무의미하다 — 암호문의 정렬 순서는 평문과 아무 관계가 없다. LIKE 부분검색도 불가능하다.

즉 강한 암호화일수록 검색성이 0이 된다. 이건 트레이드오프가 아니라 정의다. 결정적(deterministic) 암호화로 바꾸면 같은 평문 → 같은 암호문이라 동등 검색은 가능해지지만, 패턴 노출이라는 보안 비용을 다시 지불한다.

블라인드 인덱스로 검색 복구

동등 검색만 필요하다면 블라인드 인덱스(blind index)가 표준 해법이다. 평문을 키가 있는 해시(HMAC)로 변환한 값을 별도 컬럼에 저장하고, 그 컬럼으로 검색한다. HMAC은 결정적이라 같은 입력 → 같은 출력이므로 동등 검색이 가능하다. 동시에 키 없이는 역산이 불가능하다.

1
2
3
4
5
6
CREATE TABLE users (
    id          BIGINT PRIMARY KEY,
    phone_enc   VARBINARY(256),  -- AES 암호문 (랜덤 IV, 복호화용)
    phone_bidx  CHAR(64),        -- HMAC-SHA256(phone) (검색용)
    INDEX idx_phone_bidx (phone_bidx)
);
1
2
3
4
5
6
7
8
// 저장: 두 표현을 함께 기록
user.setPhoneEnc(encryptor.encrypt(phone));        // 보관·표시용
user.setPhoneBidx(blindIndex.compute(phone));      // 검색용

// 검색: 입력을 같은 HMAC으로 변환해 매치
String bidx = blindIndex.compute(inputPhone);
List<User> found = userRepo.findByPhoneBidx(bidx);
// 매치된 행만 phone_enc를 복호화해 실제 값 확인

원본 값은 phone_enc(강한 암호화, 표시용), 검색은 phone_bidx(HMAC, 색인 가능)로 역할을 분리한다. 블라인드 인덱스는 동등 일치만 지원한다 — 범위·부분 검색은 여전히 불가능하다.

키 관리가 본질이다

암호화의 안전성은 알고리즘이 아니라 키 관리에 달렸다. 키를 소스 코드나 같은 DB에 평문으로 두면 암호화는 장식일 뿐이다. 키는 별도의 키 관리 서비스(KMS)나 시크릿 저장소에 두고, 애플리케이션은 런타임에만 불러온다. 또 키 교체(rotation)를 대비해 어떤 키로 암호화했는지 식별자를 암호문에 함께 저장해야, 키를 바꿔도 과거 데이터를 복호화할 수 있다.

운영 함정

1. 암호화 컬럼으로 정렬·범위 검색 금지. “전화번호 오름차순”이나 “범위 검색”이 요구되면 블라인드 인덱스로도 안 된다. 설계 단계에서 어떤 검색이 필요한지부터 못 박아야 한다.

2. 컬럼 길이를 암호문 기준으로 잡아라. 암호화하면 IV·패딩·인코딩으로 길이가 늘어난다. 평문 길이로 컬럼을 잡으면 저장 시 잘려서 복호화가 깨진다.

핵심 요약

  • 강한 저장 암호화는 랜덤 IV로 매번 다른 암호문을 만들고, 그래서 검색·정렬이 불가능하다.
  • 동등 검색이 필요하면 HMAC 기반 블라인드 인덱스를 별도 컬럼에 둔다(부분·범위는 여전히 불가).
  • 보안은 키 관리에서 결정된다 — 키는 분리 저장, 교체 대비 키 식별자 동봉.
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.