맞춤형 PII 정책 추가가 콘솔에서 정책을 만들고 적용하는 절차를 다룬다면, 이 페이지는 규칙의 내용을 다룹니다 — 무엇을 어느 필드에 적어야 탐지 엔진이 정확하게 동작하는지, 그리고 규칙들이 서로 충돌하지 않도록 우선순위를 어떻게 설계하는지. 모든 예시는 Starfort가 제공하는 기본 PII 정책(한국형 주민등록번호·여권·운전면허·휴대폰·계좌·카드 등 27개 정규식 + NER 3종 + 키워드)에서 발췌했습니다.
정책 구조와 처리 순서
PII 정책은 세 가지 규칙 배열로 구성됩니다. 허용되는 최상위 키는 ner, regex, keyword이며, 엔진은 항상 Keyword → Regular Expression → NER 순서로 검사합니다. 앞 단계가 확정한 텍스트는 뒤 단계에 가려진 상태로 전달되므로, 앞 단계의 판정이 그 텍스트에 대해 최종입니다.
| 규칙 유형 | 특성 | 적합한 대상 |
|---|
| Keyword | 대소문자 구분 정확 일치. 가장 빠르고 결정적 | 내부 코드네임, 알려진 안전 값(allowlist) |
| Regular Expression | 패턴 일치. 결정적 | 형식이 고정된 식별자(주민등록번호, 전화번호, 카드번호, 이메일) |
| NER Entity | AI 모델 탐지. 문맥 이해 | 문맥에 의존하는 정보(이름, 주소), 패턴이 놓치는 변형 |
우선순위 설계
규칙을 늘릴수록 규칙끼리의 상호작용이 결과를 좌우합니다. 세 가지 우선순위를 기억하세요.
- 규칙 유형 우선순위: Keyword > Regular Expression > NER. 앞 단계가 확정한 텍스트는 뒤 단계가 다시 판정하지 않습니다.
- PASSING은 allowlist입니다.
policy_type: "PASSING" 규칙이 매치한 텍스트는 안전으로 확정되어, 이후 어떤 마스킹·차단 규칙도 덮어쓰지 못합니다. 같은 유형 안에서 같은 텍스트를 두 규칙이 매치하면 id가 낮은 규칙이 우선합니다.
- action 우선순위: BLOCK > MASK > PASS. 요청 안에서 규칙 하나라도 BLOCK을 결정하면, 다른 규칙이 마스킹만 했더라도 요청 전체가 차단됩니다.
기본 정책은 이 원칙을 그대로 활용합니다. 실데이터 마스킹 정규식(id 10 이상)보다 앞선 id(0–9)에 테스트 패턴 PASSING 규칙을 배치해, 문서 예시나 QA에 쓰이는 더미 값이 마스킹되지 않게 합니다:
{
"id": 0,
"rule_id": "test_data:_resident_number_test_pattern",
"regex": "(?<!\\d)(?:(\\d)\\1{5}[-\\. ]\\1{7}|(?:000000|111111|222222|333333|999999|123456|000101|010101|990101)[-\\. ](?:0000000|1111111|2222222|9999999|1234567))(?!\\d)",
"description": "000000-0000000, 111111-1111111, 123456-1234567 (주민번호 테스트)",
"policy_type": "PASSING",
"mask_word": "TEST_DATA",
"alert_message": "test data pattern - allowed"
}
같은 목적의 keyword 규칙도 있습니다 — 예시 문서의 단골 이름 홍길동을 PASSING으로 선점해, NER 이름 규칙이 마스킹하지 못하게 합니다. Keyword 단계가 NER보다 먼저 실행되기 때문에 확실하게 동작합니다.
Regular Expression 규칙 작성
기본 정책의 주민등록번호 규칙입니다:
{
"id": 10,
"rule_id": "resident_number:_all_gender_with_separators",
"regex": "(?<!\\d)(?:[0-9]{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12][0-9]|3[01]))[-\\. ][1-8]\\d{6}(?!\\d)",
"description": "901231-1234567, 901231-5234567, 901231.1234567, 901231 1234567",
"policy_type": "MASKING",
"mask_word": "RESIDENT_NUMBER",
"alert_message": "resident number detected"
}
이 규칙이 보여주는 작성 관행:
- 숫자 경계를 고정하세요. 앞뒤의
(?<!\d) / (?!\d)가 없으면 더 긴 숫자열(계좌번호, 바코드)의 중간 조각이 주민등록번호로 오탐됩니다.
description에 매치 예시를 기록하세요. 이 필드는 탐지에 쓰이지 않지만, 나중에 규칙을 검토하는 사람이 패턴을 다시 해독하지 않아도 되게 합니다.
- 다른 규칙과의 충돌을 패턴에서 해결하세요. 기본 정책의 휴대폰 규칙은 후행
(?![-\.]?\d) 가드를 두어, 013-12345678-901 같은 은행 계좌번호의 앞부분을 전화번호로 선점하지 않게 합니다.
빈 문자열에 매치될 수 있는 패턴(\d*, secret|)은 아무것도 탐지하지 못하고 건너뛰어집니다. 또한 패턴 앞뒤의 공백은 저장 시 정리되므로, 의도적인 경계 공백은 \s나 [ ]처럼 패턴 안에 표현하세요.
NER Entity 규칙 작성
NER 규칙에서 AI 모델에 전달되는 필드는 Name, Description, Positive Examples, Negative Examples 네 가지뿐입니다. Policy Type, Mask Word, Alert Message는 탐지 이후의 처리만 결정하며 탐지 자체에는 영향을 주지 않습니다. 즉, 탐지 정확도를 좌우하는 것은 앞의 네 필드입니다.
기본 정책의 한국 주소 규칙을 설명에 맞춰 간추린 예시입니다. 이 규칙의 핵심은 구체성의 경계입니다 — 같은 “위치 이야기”라도 특정 개인·사업장을 찾아갈 수 있을 만큼 구체적이면 민감정보이고, 일반적인 위치 언급이면 아닙니다. 아래 각 절이 예시의 어느 부분을 가리키는지 보면서 읽어보세요:
{
"id": 2,
"name": "주소 (한국)",
"description": "특정 개인이나 사업장의 위치를 식별할 수 있는 한국 주소. 반드시 도로명+건물번호 또는 동/리+번지 같은 구체적 요소를 포함해야 하며, 동·호·층 같은 상세 정보가 따라올 수 있다. 랜드마크, 지하철역 출구, 건물명 단독, 번지 없는 행정구역 같은 일반적인 위치 언급은 주소가 아니다.",
"policy_type": "MASKING",
"mask_word": "ADDRESS",
"alert_message": "주소 감지됨",
"positive_examples": [
"서울특별시 강남구 테헤란로 152 강남파이낸스센터 28층 →테헤란로 152 강남파이낸스센터 28층",
"거주지: 서울 서초구 반포동 123-45 래미안 아파트 503동 201호 →반포동 123-45 래미안 아파트 503동 201호",
"사무실 주소는 종로구 새문안로 76 에스타워 12F입니다 →새문안로 76 에스타워 12F"
],
"negative_examples": [
"강남역 11번 출구에서 만나",
"스타벅스 종로점에서 보자",
"신사동 가로수길 카페 추천"
]
}
Description — 정의 + 구체성 조건
위 Description은 네 가지 요소를 순서대로 담고 있습니다: 정의(개인·사업장 위치 식별), 필수 구체성 조건(“도로명+건물번호 또는 동/리+번지”), 허용 변형(동·호·층 상세), 그리고 제외 조건(랜드마크, 지하철역 출구, 건물명 단독, 번지 없는 행정구역). 민감/비민감을 가르는 경계선을 Description이 문장으로 그어주는 것입니다 — 모델은 “이 경우는 아니다”라고 적힌 케이스에 NO라고 답하도록 지시받으므로, 제외 조건은 실제로 동작합니다. 아래 시나리오 3이 이 경계가 실전에서 갈리는 모습을 그대로 보여줍니다.
Positive Examples — 화살표 규약
모든 긍정 예시는 문맥 →값 형태로 작성합니다. 모델은 → 뒤가 탐지해야 할 정확한 값이라고 학습합니다.
→ 앞의 문장은 언제 발동할지(재현율)를, → 뒤의 값은 정확한 출력 형태(정밀도)를 가르칩니다.
- 값은 마스킹 범위도 가르칩니다. 위 세 예시 모두 값이 광역 단위(서울특별시, 서초구 등)를 빼고 구체 요소부터 시작합니다 — 규칙이 어디서부터 어디까지를 민감정보로 볼지, 예시의 값으로 알려주는 것입니다.
- 값은 입력에서 다시 찾을 수 있어야 합니다. 나타난 그대로 적는 것이 가장 안전하며(공백 차이 정도는 허용), 도로명과 건물명을 재배열하는 식으로 재구성한 값은 위치를 찾지 못해 버려집니다.
- 위 세 예시는 실제로 등장할 표면 형태를 하나씩 가르칩니다: 도로명 주소 기본형, 지번(동+번지)과 호실이 붙는 변형, 레이블 없이 서술문 안에 박힌 주소. 놓치면 안 되는 형태마다 예시를 하나씩 두세요.
- 잡으려는 데이터의 언어로 예시를 쓰세요 — 한국 주소라면 한국어 예시로.
Negative Examples — 오탐 방어막
형식은 비슷하지만 구체성이 부족한 근접 사례를 담으세요. 위 세 negative는 각각 다른 오탐 경로를 막습니다: 강남역 11번 출구(만남 장소로 쓰이는 랜드마크 — 숫자가 있어도 주소가 아님), 스타벅스 종로점(상호+지점명), 신사동 가로수길(번지 없는 동네 이름). 셋 다 Description의 제외 조건과 짝을 이룹니다. NER 규칙은 소규모 배치로 함께 스크리닝되므로, 한 규칙의 부실한 negative가 이웃 규칙의 과탐까지 유발할 수 있습니다.
Keyword 규칙 작성
Keyword는 대소문자를 구분하는 정확 일치입니다. 문맥을 보지 않으므로 짧고 일반적인 단어는 피하세요.
- 좋은 BLOCKING 키워드:
PROJECT-ORION 같은 내부 코드네임 — 어디서 나오든 그 자체로 민감.
- 좋은 PASSING 키워드: 기본 정책의
홍길동 — 알려진 안전 값을 선점해 뒤 단계가 건드리지 못하게 하는 allowlist.
- 나쁜 키워드:
계정 같은 일반 명사 — 등장하는 모든 곳에서 무차별 발동.
예시 시나리오
기본 PII 정책이 할당된 Guardian에 요청을 보냈을 때의 동작입니다.
시나리오 1 — 휴대폰 번호 마스킹
“제 번호는 010-2543-2513입니다. 010.5364.1451로도 연락 돼요.”
휴대폰 정규식이 두 값을 모두 매치합니다. 결과는 "action": "MASK", 본문은 제 번호는 [PHONE_NUMBER_1]입니다. [PHONE_NUMBER_2]로도 연락 돼요. — 마스크 단어에는 등장 순서대로 인덱스가 붙습니다.
시나리오 2 — 테스트 데이터는 통과, 실데이터는 마스킹
“테스트 계정 주민번호는 990101-1234567, 실계정은 901231-1234567입니다.”
990101-1234567은 날짜가 유효해 주민등록번호 마스킹 규칙(id 10)에도 매치되지만, 잘 알려진 테스트 값이라 PASSING 테스트 패턴(id 0)이 먼저 선점해 그대로 통과합니다. 901231-1234567만 마스킹되어 결과는 ... 990101-1234567, 실계정은 [RESIDENT_NUMBER_1]입니다. — allowlist 규칙이 실데이터 규칙보다 낮은 id를 가진 이유입니다.
시나리오 3 — 구체적인 주소만 민감정보
“미팅은 강남역 11번 출구 앞 카페에서 해요. 계약서는 서울 강남구 테헤란로 152 강남파이낸스센터 28층으로 보내주세요.”
같은 문장에 위치 언급이 두 번 나오지만 판정이 갈립니다. 강남역 11번 출구는 숫자가 있어도 만남 장소 수준의 일반 언급이라 — Description의 제외 조건과 negative example이 학습시킨 대로 — 통과합니다. 도로명+건물번호가 있는 구체 주소만 마스킹되고, 값이 가르친 대로 마스킹 범위는 구체 요소부터 시작합니다: 미팅은 강남역 11번 출구 앞 카페에서 해요. 계약서는 서울 강남구 [ADDRESS_1]으로 보내주세요.
시나리오 4 — BLOCK은 전부를 이깁니다
마스킹 규칙 열 개가 매치하고 BLOCKING 규칙 하나가 매치하면, 결과는 "action": "BLOCK"이고 마스킹된 본문은 반환되지 않습니다. 유출 자체를 막아야 하는 값(사내 기밀 코드네임 등)에만 BLOCKING을 쓰고, 나머지는 MASKING으로 두는 것이 좋습니다.
체크리스트
- 정규식에 숫자·단어 경계(
(?<!\d), (?!\d))를 넣었는가?
- 테스트·예시 값이 있다면 PASSING 규칙으로 먼저 선점했는가?
- NER Description에 정의 + 구체성·문맥 조건 + 제외 조건을 적었는가?
- Positive Examples를
문맥 →값 형태로, 값이 마스킹 범위를 정확히 가리키게 적었는가?
- Negative Examples에 구체성이 부족한 근접 사례를 담았는가?
- BLOCKING은 정말 차단이 필요한 규칙에만 썼는가?
규칙 정의 전체는 Starfort 기본 PII 정책에서 볼 수 있습니다 — 콘솔의 JSON 편집기로 불러온 뒤 필요한 규칙만 남기고 다듬는 것이 가장 빠른 시작 방법입니다. 콘솔 정책 페이지의 TIP 버튼에서도 이 가이드의 요약을 볼 수 있습니다.
규칙 수와 예시 분량은 곧 탐지 비용입니다. 모든 호출에 규칙 정의 전체가 전달되므로, 지나치게 장황한 정책은 응답을 느리게 하고 극단적으로는 모델 입력 한도를 넘겨 요청을 실패시킵니다. 규칙당 날카로운 예시 5~10개가 망라식 나열보다 낫습니다.