개발·QA 환경에는 “실제 같은” 데이터가 필요하다. 그렇다고 프로덕션을 그대로 복사하면 전화번호·이름·생년월일 같은 PII가 비운영 환경에 그대로 흘러간다. 그 사이 균형을 잡는 마스킹 전략을 정리한다.
두 가지 접근
- 생성(synthetic) — 규칙에 맞는 가짜 데이터를 처음부터 만든다. 유출 위험이 없지만, 실제 분포·엣지케이스를 재현하기 어렵다.
- 마스킹(masking) — 운영 데이터를 복사하되 민감 필드를 치환한다. 현실성은 높지만, 참조 무결성과 포맷을 지키는 게 관건이다.
실무에선 둘을 섞는다. 뼈대는 마스킹으로 현실성을 얻고, 민감·희소 케이스는 생성으로 채운다.
지켜야 할 것
1. 포맷·제약 유지
마스킹해도 컬럼의 형식(길이·체크·유니크)을 깨면 안 된다. 전화번호는 전화번호처럼, 생년월일은 유효한 날짜로.
010-1234-5678 → 010-3487-9021 (형식 유지)
홍길동 → 홍** (길이/타입 유지)
1990-03-15 → 1990-07-22 (유효 날짜, 연령대 유지)
2. 참조 무결성 = 결정적 마스킹
같은 원본 값은 항상 같은 마스킹 값으로 바뀌어야 한다(deterministic). 그래야 FK·조인이 깨지지 않는다. 랜덤이 아니라 해시 기반으로 치환한다.
-- 같은 입력 → 항상 같은 출력 (조인 유지)
UPDATE agreement
SET service_number = CONCAT('SMN', LPAD(CONV(SUBSTRING(SHA2(service_number,256),1,8),16,10) % 100000000, 8, '0'));
Warning
단순 랜덤 치환은 FK로 연결된 테이블 간 관계를 깨뜨린다. “결정적”이 핵심 — 같은 키는 모든 테이블에서 동일하게 변환돼야 한다.
3. 필드별 전략
| 필드 | 전략 |
|---|---|
| 이름 | 성만 남기고 마스킹, 또는 이름 사전에서 대체 |
| 전화/식별번호 | 접두·접미만 남기고 중간 마스킹, 또는 결정적 재생성 |
| 생년월일 | 연/월 유지 + 일 변경, 또는 연령대만 보존 |
| 이메일 | 로컬파트 해시 + 테스트 도메인 |
| 금액·수량 | ± 노이즈 추가(분포 보존) 또는 그대로(민감치 아님) |
4. 민감 컬럼은 뷰로도 이중 방어
마스킹된 데이터셋을 만들더라도, 접근 계층에서 마스킹 뷰로 한 번 더 감싸면 실수로 원본을 노출할 여지를 줄인다.
정리
- 프로덕션 복사 = PII 유출. 마스킹/생성으로 걸러서 반출
- 포맷·제약 유지, 유효한 값으로
- 참조 무결성은 결정적(해시 기반) 마스킹으로 지킨다
- 필드별 전략을 정하고, 뷰로 이중 방어
한 번 마스킹 파이프라인을 만들어두면 비운영 환경 데이터 갱신이 “버튼 하나”가 된다.