DB 컬럼 암호화는 “무엇을 막고 싶은지”에 따라 방식이 달라진다.
실무 기준으로 조회 가능성, 성능, 키 관리까지 같이 묶어서 정리해보자.



DB 컬럼 암호화는 실무에서 보통:
특정 민감 컬럼만 AES로 암호화해서 저장
하는 구조를 말한다.
예:
- 주민번호
- 계좌번호
- 전화번호
- 이메일
- 카드번호
같은 것들.
가장 기본 구조
보통 흐름은 이렇다.
애플리케이션
↓
AES 암호화
↓
DB 저장
조회할 때는:
DB 조회
↓
AES 복호화
↓
화면 표시
핵심은 "DB가 원문을 모르게"
즉 DB 내부에는:
홍길동
01012345678
가 아니라:
X82JK...
AB91Q...
같은 암호문 저장.
실무에서 제일 많이 쓰는 방식
애플리케이션 레벨 암호화
가장 흔하다.
구조:
Java/Spring
↓ AES-GCM
암호화
↓
Oracle/MySQL/Postgres 저장
예시
String encrypted = aes.encrypt(phoneNumber);
DB에는:
9AFA82B1...
저장된다.
왜 AES를 쓰나?
컬럼 데이터는:
- 복호화 필요
- 조회 필요
- 빠른 속도 필요
하기 때문이다.
그래서 대부분:
- Advanced Encryption Standard
- AES-GCM
- AES-CBC(구식)
사용.
현재는 거의 AES-GCM 권장이다. 암호화와 무결성 검증을 같이 처리할 수 있기 때문이다.
구조적으로 보면
원문 데이터
↓
AES 암호화
↓
IV/Nonce 생성
↓
암호문 + Tag 저장
실제 DB 저장 형태
예:
| 컬럼 | 저장값 |
| phone_enc | Base64 암호문 |
| nonce | IV( 랜덤값 )/nonce |
| tag | 인증태그 |
혹은:
[nonce][ciphertext][tag]
합쳐서 저장하기도 한다.
중요한 문제 — 검색이 어려움
암호화하면:
WHERE phone = ?
같은 검색이 안 된다.
왜냐면 같은 값도 nonce 때문에:
매번 다른 암호문
되기 때문이다.
그래서 실무에서 많이 쓰는 구조
분리구조 : 1.암호화 컬럼 (복호화용) + 2.해시 컬럼 (검색용)
예:
| 컬럼 | 역할 |
| phone_enc | 복호화용 AES |
| phone_hash | 검색용 SHA-256 |
예시
01012345678
↓
AES → 복호화 가능 저장
↓
SHA-256 → 검색용 저장
조회할 때
WHERE phone_hash = SHA256('01012345678' + pepper)
즉, 표시는 복호화, 검색은 해시로 처리.
로그인 비밀번호와 차이
엄청 중요하다.
비밀번호
복호화 절대 안 함
→ bcrypt/Argon2 해시값 저장
컬럼 암호화
나중에 다시 보여줘야 함
→ AES 암호화 저장
예를 들어
주민번호
고객센터에서 다시 봐야 함.
→ AES 필요.
비밀번호
운영자도 보면 안 됨.
→ 해시만 저장.
키 관리가 핵심
사실 컬럼 암호화에서 제일 중요한 건 암호화 알고리즘보다 키 관리이다:
AES 키를 어디 보관하느냐
다.
위험한 구조
# 소스코드에 하드코딩
private static final String KEY = "1234567890123456";
실무에서 매우 위험.
보통 실무에서는 외부 키 관리
방법 1
환경변수.
ENV KEY
방법 2
KMS 사용.
예:
- Amazon Web Services KMS
- Google Cloud KMS
- Microsoft Key Vault
애플리케이션
↓
KMS에게 요청
"DEK 복호화 해줘"
↓
KMS 내부에서만 CMK 사용
↓
복호화된 DEK 반환
↓
앱이 AES 암호화 수행
즉:
앱이 CMK 원문을 직접 들고있지 않음
그림으로 이해
전화번호
↓ DEK로 암호화
암호문
DEK
↓ CMK로 암호화
Encrypted DEK
왜 2단계 키 구조를 쓰냐
핵심은:
키 교체(rotation)
때문.
나쁜 구조
데이터를 AES키 하나로만 암호화
문제:
키 바꾸려면:
DB 전체 재암호화
해야 함.
대규모 서비스면 사실상 지옥.
좋은 구조
데이터는 DEK로 암호화
DEK만 CMK로 감쌈
CMK 교체 시:
DEK만 다시 암호화
하면 끝.
엄청 효율적.
(NIST도 암호화 키의 생성, 보관, 교체, 폐기 같은 키 수명주기 관리가 중요하다고 설명함)
정리
비밀번호 → Argon2 / bcrypt 해시
개인정보 표시용 → AES-256-GCM 암호화
검색/중복체크 → SHA-256/HMAC 해시 컬럼 별도 저장
암호화 키 → 소스코드/DB에 두지 말고 KMS/Vault/환경변수 관리
가장 현실적인 기본 구조는:
원문 → 애플리케이션에서 AES-GCM 암호화 → DB 저장
원문 → HMAC-SHA256 → 검색용 컬럼 저장
| 컬럼 | 값 |
| phone_enc | AES(01012345678) |
| phone_hash | HMAC_SHA256(01012345678) |
즉 조회 시
01012345678를 검색하면
애플리케이션 서버에서 HMAC_SHA256(01012345678) = > A1B2C3D4... 해시값이 전달됨 (로그에도 해시값만 노출. 앱 메모리에는 입력값으로 존재할 순 있으나 일반적이로 남지는 않으니까 패스)
SELECT *
FROM USER
WHERE phone_hash = 'A1B2C3D4...'
있는 row의 phone_enc를 앱서버에서 AES복호화
컬럼 암호화 (AES) vs TDE
많이 헷갈린다.
TDE(Transparent Data Encryption)
예:
- Oracle TDE
- MSSQL TDE
특징
DB 파일 자체 암호화
즉:
- 디스크 탈취 방어
- DBA는 평문 조회 가능, SQL Injection, 내부 계정 탈취에는 약함
컬럼 암호화(AES)
특정 컬럼만 애플리케이션 레벨 암호화
즉 DBA도 원문 못 보게 가능. SELECT 해도 암호문만 보임
비교
| 공격 | TDE컬럼 | AES(컬럼암호화) |
| 디스크 탈취 | 강함 | 강함 |
| 백업 유출 | 강함 | 강함 |
| DBA 평문조회 | 약함 | 강함 |
| SQL Injection | 약함 | 강함 |
| 앱 서버 탈취 | 약함 | 약함 |
실무에서 자주 쓰는 패턴
실무 보안 수준
= 민감 컬럼 암호화(AES)
+ 검색용 해시(HMAC/SHA) 컬럼 추가
+ TDE
를 같이 쓰는 경우가 많음
전화번호
AES 저장
SHA-256 검색
카드번호
보통:
- 일부 마스킹 저장
- 일부만 복호화 가능
주민번호
강한 AES + 접근통제.
Java 실무 스타일
보통:
- JCE(Java Cryptography Extension)
- Spring AOP
- MyBatis TypeHandler
- JPA Converter
등으로 자동 암복호화 구현한다.
특히 많이 쓰는 구조
MyBatis:
조회 시 자동 복호화
저장 시 자동 암호화
TypeHandler 구조 많이 쓴다.
핵심 요약
DB 컬럼 암호화는 보통:
민감 컬럼을 AES로 암호화 저장하고,
필요 시 애플리케이션에서 복호화하는 방식
이며,
실무 핵심은:
암호 알고리즘보다
"키 관리"와 "검색 구조 설계"
다.
'system_fundamentals > security_cryptography' 카테고리의 다른 글
| RSA 원리 (0) | 2026.05.14 |
|---|---|
| 공개키 암호화는 어떻게 가능한가 (0) | 2026.05.14 |
| 용어정리 (0) | 2026.05.14 |
| 파일 암호화 구조 (0) | 2026.05.14 |
| 스트림 암호 vs 블록 암호 (0) | 2026.05.14 |
댓글