feat: 지정판매소 개인정보(PII) 보호 — 마스킹·암호화·열람 게이트 (기본 OFF)

종량제3 세션 작업. 마스터 플래그(Config\Pii.designatedShopProtection)가 OFF면
현재 동작(원문 그대로) 유지, ON일 때만 마스킹·게이트 적용.

- 표시 계층 단일 지점 마스킹: 대표자명/전화/이메일/계좌/가상계좌 (목록·상세·엑셀·판매대장·전화주문)
- 원문 열람 게이트: 지자체 허용 IP 자동열람 or 2단계 인증(TOTP) step-up + 감사기록(revealPii)
- 정확일치 검색: 블라인드 인덱스(HMAC) 컬럼 있으면 사용, 없으면 평문 폴백
- 저장계층 암호화(encryptAtRest, 기본 OFF): 모델 콜백 + spark 명령 pii:protect-designated-shops
- SQL(추가·멱등): designated_shop_add_pii_bidx / local_government_add_allow_ips
- Auth: TOTP 실제 통과 시에만 세션 auth_2fa_verified=true

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
taekyoungc
2026-07-16 15:45:28 +09:00
parent c5df784f91
commit 5e8e81f404
12 changed files with 726 additions and 19 deletions

View File

@@ -0,0 +1,23 @@
-- 지정판매소 PII 블라인드 인덱스 컬럼(정확일치 검색용) 추가 — HMAC-SHA256 값 저장(64 hex)
-- 실행: mysql -u jongryangje -p jongryangje_dev < writable/database/designated_shop_add_pii_bidx.sql
-- 멱등. 컬럼 추가 후, 암호화/백필은 spark 명령(pii:protect-designated-shops)으로 수행.
SET @db = DATABASE();
SET @sql = IF((SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='designated_shop' AND COLUMN_NAME='ds_tel_bidx')>0,
'SELECT ''ds_tel_bidx exists''',
'ALTER TABLE `designated_shop` ADD COLUMN `ds_tel_bidx` CHAR(64) NOT NULL DEFAULT '''' COMMENT ''전화 블라인드인덱스(HMAC)'' , ADD INDEX `idx_ds_tel_bidx` (`ds_tel_bidx`)');
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
SET @sql = IF((SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA=@db AND TABLE_NAME='designated_shop' AND COLUMN_NAME='ds_rep_name_bidx')>0,
'SELECT ''ds_rep_name_bidx exists''',
'ALTER TABLE `designated_shop` ADD COLUMN `ds_rep_name_bidx` CHAR(64) NOT NULL DEFAULT '''' COMMENT ''대표자명 블라인드인덱스(HMAC)'' , ADD INDEX `idx_ds_rep_name_bidx` (`ds_rep_name_bidx`)');
PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s;
-- 참고: 암호문(ENC:...)은 평문보다 길어짐. 아래 PII 컬럼이 짧으면 길이 확대 필요할 수 있음(확인 후 조정).
-- ALTER TABLE `designated_shop`
-- MODIFY `ds_rep_name` VARCHAR(255) NULL, MODIFY `ds_tel` VARCHAR(255) NULL,
-- MODIFY `ds_rep_phone` VARCHAR(255) NULL, MODIFY `ds_email` VARCHAR(255) NULL,
-- MODIFY `ds_va_account` VARCHAR(255) NULL;

View File

@@ -0,0 +1,15 @@
-- 지자체별 허용 IP 대역(CIDR/단일IP, 쉼표·공백 구분) — 지정판매소 PII 자동 원문 열람 조건에 사용
-- 실행: mysql -u jongryangje -p jongryangje_dev < writable/database/local_government_add_allow_ips.sql
-- 멱등(이미 있으면 건너뜀).
--
-- 예시 값(운영 반영 시 각 지자체 실제 사무실 공인 IP로 UPDATE):
-- UPDATE local_government SET lg_allow_ips = '203.0.113.10, 203.0.113.0/24' WHERE lg_idx = 1;
SET @db = DATABASE();
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'local_government' AND COLUMN_NAME = 'lg_allow_ips') > 0,
'SELECT ''lg_allow_ips already exists'' AS msg',
'ALTER TABLE `local_government` ADD COLUMN `lg_allow_ips` VARCHAR(500) NOT NULL DEFAULT '''' COMMENT ''허용 IP 대역(CIDR/단일IP, 쉼표구분) — PII 자동 원문 열람'''
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;