개인정보보호 기능개선 5차 — comvnusermaster/comvnuserinfo 뷰 GNR 컷오버 DDL 실행분 커밋

회원정보 암호화(Action4)의 마지막 단계. 545b49d로 반영한 소비자 정비(66개 표시 +
전체 검색전환)를 전제로, 두 공유 뷰의 GNR 분기를 MBER_NM(평문)에서 MBER_NM_ENC(암호문)로
전환하고 검색용 USER_NM_HASH 컬럼을 추가하는 DDL을 127.0.0.1:3306 dev DB에 실제 실행했다.

- information_schema.views.VIEW_DEFINITION을 서버사이드 REPLACE()로 최소 치환(PREPARE/
  EXECUTE) — comvnuserinfo의 한글 리터럴(USER_GUBUN_NM)을 클라이언트에서 재입력하지
  않아 터미널 인코딩 문제를 원천 회피
- 실행 전 원본 정의를 privacy_view_def_backup 테이블에 백업, 치환 건수/컬럼 존재
  여부를 assertion으로 강제해 잘못된 정의 반영을 차단
- 행 수(USER_SE/USER_GUBUN별 COUNT) 실행 전후 동일 확인, GNR 표본 암호문+해시 노출
  확인, USR/ENT 표본 평문 그대로 유지 확인 — 상세 로그는 _workspace/deploy/20260811_0850/
  DB_APPLY_LOG.md(gitignored, 로컬 전용)

주의: 이번엔 코드(545b49d) 커밋 후 로컬 WAS 재기동 전에 DB DDL을 먼저 실행했다 —
다음 반영 시 코드부터 배포하고 재기동할 것(LAST_DEPLOYED.md 참조).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
infraurp 2026-08-11 09:14:38 +09:00
parent 545b49daf7
commit 1be7d84e88

View File

@ -0,0 +1,160 @@
-- 개인정보보호 기능개선 사업 추가제안 Action4 (2026-08-11)
-- comvnusermaster / comvnuserinfo 뷰 재정의: GNR 분기를 암호문(MBER_NM_ENC)으로 전환하고
-- 검색용 해시 컬럼(USER_NM_HASH)을 추가한다.
--
-- 주의: 이 스크립트는 기존 뷰의 정확한 바이트 내용(특히 comvnuserinfo의 한글 리터럴
-- USER_GUBUN_NM 값)을 절대 재입력하지 않는다 — information_schema.views.VIEW_DEFINITION을
-- 서버 사이드에서 REPLACE()로 최소 치환만 하고, 결과를 다시 CREATE OR REPLACE VIEW로
-- 반영한다(PREPARE/EXECUTE 동적 SQL). 클라이언트 터미널 인코딩 문제로 한글이 깨져
-- 보이는 현상과 무관하게 안전하다.
--
-- VIEW_DEFINITION은 테이블명을 스키마 한정자(`csv`.`table`)로 저장한다는 점에
-- 주의(SHOW CREATE VIEW의 표시와 다름) — 2026-08-11 dryrun으로 실측 확인.
--
-- 사전조건: 이 스크립트를 실행하기 전에 comvnusermaster/comvnuserinfo를 소비하는
-- 모든 구문(66개 표시 + 검색 전환분, 2026-08-11 커밋 545b49d)이 이미 반영되어 있어야
-- 한다 — all-or-nothing 게이트. 되돌리려면 아래 백업 섹션의 CREATE OR REPLACE VIEW로 복원한다.
-- ============================================================
-- 0. 백업: 현재 뷰 정의를 별도 테이블에 저장(롤백용)
-- ============================================================
CREATE TABLE IF NOT EXISTS privacy_view_def_backup (
view_name VARCHAR(64) NOT NULL,
backup_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
view_definition MEDIUMTEXT NOT NULL,
PRIMARY KEY (view_name, backup_at)
);
INSERT INTO privacy_view_def_backup (view_name, view_definition)
SELECT 'comvnusermaster', VIEW_DEFINITION
FROM information_schema.views
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'comvnusermaster';
INSERT INTO privacy_view_def_backup (view_name, view_definition)
SELECT 'comvnuserinfo', VIEW_DEFINITION
FROM information_schema.views
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'comvnuserinfo';
SELECT view_name, COUNT(*) AS backup_count FROM privacy_view_def_backup GROUP BY view_name;
-- ============================================================
-- 1. comvnusermaster 재정의
-- ============================================================
SET @def_master = (
SELECT VIEW_DEFINITION FROM information_schema.views
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'comvnusermaster'
);
SET @def_master = REPLACE(
@def_master,
'`comtngnrlmber`.`MBER_NM` AS `USER_NM`',
'`comtngnrlmber`.`MBER_NM_ENC` AS `USER_NM`'
);
SET @def_master = REPLACE(
@def_master,
'end) AS `ADULT` from `csv`.`comtngnrlmber` where',
'end) AS `ADULT`,`csv`.`comtngnrlmber`.`MBER_NM_HASH` AS `USER_NM_HASH` from `csv`.`comtngnrlmber` where'
);
SET @def_master = REPLACE(
@def_master,
'\'N\' AS `ADULT` from `csv`.`comtnemplyrinfo` union all',
'\'N\' AS `ADULT`,NULL AS `USER_NM_HASH` from `csv`.`comtnemplyrinfo` union all'
);
SET @def_master = REPLACE(
@def_master,
'\'N\' AS `ADULT` from `csv`.`comtnentrprsmber` where',
'\'N\' AS `ADULT`,NULL AS `USER_NM_HASH` from `csv`.`comtnentrprsmber` where'
);
SET @def_master = REPLACE(
@def_master,
'\'N\' AS `ADULT` from `csv`.`biz_group` where',
'\'N\' AS `ADULT`,NULL AS `USER_NM_HASH` from `csv`.`biz_group` where'
);
-- 안전장치: 치환이 정확히 4건(분기당 1건)이 아니면 실행을 중단시킨다(0으로 나누기 강제 에러).
SELECT CASE WHEN
(LENGTH(@def_master) - LENGTH(REPLACE(@def_master, 'USER_NM_HASH', ''))) / LENGTH('USER_NM_HASH') = 4
AND @def_master LIKE '%MBER_NM_ENC%'
AND @def_master NOT LIKE '%`comtngnrlmber`.`MBER_NM` AS `USER_NM`%'
THEN 1 ELSE 1/0 END AS master_assertion_ok;
SET @sql_master = CONCAT('CREATE OR REPLACE VIEW comvnusermaster AS ', @def_master);
PREPARE stmt_master FROM @sql_master;
EXECUTE stmt_master;
DEALLOCATE PREPARE stmt_master;
-- ============================================================
-- 2. comvnuserinfo 재정의
-- ============================================================
SET @def_info = (
SELECT VIEW_DEFINITION FROM information_schema.views
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'comvnuserinfo'
);
SET @def_info = REPLACE(
@def_info,
'`comtngnrlmber`.`MBER_NM` AS `USER_NM`',
'`comtngnrlmber`.`MBER_NM_ENC` AS `USER_NM`'
);
SET @def_info = REPLACE(
@def_info,
'`comtngnrlmber`.`ADMIN_UNLOCK_DT` AS `ADMIN_UNLOCK_DT` from `csv`.`comtngnrlmber` union all',
'`comtngnrlmber`.`ADMIN_UNLOCK_DT` AS `ADMIN_UNLOCK_DT`,`csv`.`comtngnrlmber`.`MBER_NM_HASH` AS `USER_NM_HASH` from `csv`.`comtngnrlmber` union all'
);
SET @def_info = REPLACE(
@def_info,
'`biz_group`.`ADMIN_UNLOCK_DT` AS `ADMIN_UNLOCK_DT` from `csv`.`biz_group` union all',
'`biz_group`.`ADMIN_UNLOCK_DT` AS `ADMIN_UNLOCK_DT`,NULL AS `USER_NM_HASH` from `csv`.`biz_group` union all'
);
SET @def_info = REPLACE(
@def_info,
'`comtnentrprsmber`.`ADMIN_UNLOCK_DT` AS `ADMIN_UNLOCK_DT` from `csv`.`comtnentrprsmber` union all',
'`comtnentrprsmber`.`ADMIN_UNLOCK_DT` AS `ADMIN_UNLOCK_DT`,NULL AS `USER_NM_HASH` from `csv`.`comtnentrprsmber` union all'
);
SET @def_info = REPLACE(
@def_info,
'`comtnemplyrinfo`.`ADMIN_UNLOCK_DT` AS `ADMIN_UNLOCK_DT` from `csv`.`comtnemplyrinfo`',
'`comtnemplyrinfo`.`ADMIN_UNLOCK_DT` AS `ADMIN_UNLOCK_DT`,NULL AS `USER_NM_HASH` from `csv`.`comtnemplyrinfo`'
);
SELECT CASE WHEN
(LENGTH(@def_info) - LENGTH(REPLACE(@def_info, 'USER_NM_HASH', ''))) / LENGTH('USER_NM_HASH') = 4
AND @def_info LIKE '%MBER_NM_ENC%'
AND @def_info NOT LIKE '%`comtngnrlmber`.`MBER_NM` AS `USER_NM`%'
THEN 1 ELSE 1/0 END AS info_assertion_ok;
SET @sql_info = CONCAT('CREATE OR REPLACE VIEW comvnuserinfo AS ', @def_info);
PREPARE stmt_info FROM @sql_info;
EXECUTE stmt_info;
DEALLOCATE PREPARE stmt_info;
-- ============================================================
-- 3. 반영 후 검증
-- ============================================================
SELECT TABLE_NAME, COLUMN_NAME, ORDINAL_POSITION
FROM information_schema.columns
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME IN ('comvnusermaster', 'comvnuserinfo')
AND COLUMN_NAME IN ('USER_NM', 'USER_SE', 'USER_GUBUN', 'USER_NM_HASH')
ORDER BY TABLE_NAME, ORDINAL_POSITION;
SELECT USER_ID, USER_SE, LEFT(USER_NM, 20) AS user_nm_sample, LEFT(USER_NM_HASH, 20) AS hash_sample
FROM comvnusermaster WHERE USER_SE = 'GNR' LIMIT 1;
SELECT USER_ID, USER_SE, LEFT(USER_NM, 20) AS user_nm_sample, USER_NM_HASH
FROM comvnusermaster WHERE USER_SE = 'USR' LIMIT 1;
SELECT USER_SE, COUNT(*) FROM comvnusermaster GROUP BY USER_SE;
SELECT USER_GUBUN, LEFT(USER_NM, 20) AS user_nm_sample, LEFT(USER_NM_HASH, 20) AS hash_sample
FROM comvnuserinfo WHERE USER_GUBUN = 'GNR' LIMIT 1;
SELECT USER_GUBUN, COUNT(*) FROM comvnuserinfo GROUP BY USER_GUBUN;