실제 사고에서 배우는 PII 보호의 중요성
개발자가 AI API에 사용자 데이터를 전송할 때 가장 흔하게 겪는 보안 사고를 살펴보겠습니다. 다음은 실제发生过하는 시나리오입니다:
실제 발생 가능한 위험 상황
user_input = """
고객 이름: 김민수
주민등록번호: 950123-1234567
신용카드: 4532-1234-5678-9012
전화번호: 010-1234-5678
주소: 서울특별시 강남구 테헤란로 123
"""
이 데이터를 그대로 AI API에 전송하면 발생하는 문제:
1. AI가 학습 데이터로 활용할 수 있음 (데이터 유출)
2. 로그 파일에 평문으로 저장됨
3. 제3자에게 노출될 수 있는 위험
ValueError: Sensitive data detected in request payload와 같은 오류 없이 민감 정보가 그대로 전달되는 상황은 심각한 개인정보 보호법 위반입니다. 특히 금융, 의료, 보험 도메인에서는 GDPR, PCI-DSS, 개인정보보호법 준수가 법적으로 의무화되어 있습니다.
PII란 무엇인가?
PII(Personal Identifiable Information)는 특정 개인를 식별할 수 있는 모든 정보를 의미합니다. 법적 관할권에 따라 분류가 다를 수 있으나, 일반적으로 다음カテゴリ를 포함합니다:
직접 식별자 (Direct Identifiers)
DIRECT_IDENTIFIERS = {
# 한국 고유 identifiers
"resident_registration": r"\d{6}-[1-4]\d{6}", # 주민등록번호
"passport_kr": r"[A-Z]{1,2}\d{8,9}", # 여권번호
"driver_license_kr": r"\d{2}-\d{6}", # 운전면허번호
# 글로벌 identifiers
"ssn_us": r"\d{3}-\d{2}-\d{4}", # 미국 사회보장번호
"nino_uk": r"[A-Z]{2}\d{6}[A-D]", # 영국 NI 번호
# 금융 identifiers
"credit_card": r"\d{4}-\d{4}-\d{4}-\d{4}", # 신용카드
"bank_account_kr": r"\d{3}-?\d{3}-?\d{6}", # 계좌번호
# 연락처
"phone_kr": r"01[0-9]-\d{3,4}-\d{4}", # 휴대전화
"email": r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" # 이메일
}
준 식별자 (Quasi-Identifiers)
나이에 따라 통계적으로 특정 개인를 추론할 수 있는 정보들도 탈감 대상입니다:
- 나이, 성별, 국적
- 직업, 고용주 정보
- 위치 정보 (거주지, 근무지)
- 의료 정보 (진단명, 처방약)
- 고유 신체特征 (지문, 홍채)
PII 감지 아키텍처 설계
┌─────────────────────────────────────────────────────────────────┐
│ PII Protection Pipeline │
├─────────────────────────────────────────────────────────────────┤
│ │
│ [User Input] ──▶ [Preprocessor] ──▶ [PII Detector] │
│ │ │ │
│ ▼ ▼ │
│ [Normalization] [Classification] │
│ │ │ │
│ │ ┌──────┴──────┐ │
│ │ ▼ ▼ │
│ │ [Direct ID] [Quasi-ID] │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ [Masking Engine] ◀──▶ [Replacement Rules] │
│ │ │
│ ▼ │
│ [Sanitized Output] ──▶ [AI API Request] │
│ │
└─────────────────────────────────────────────────────────────────┘
실전 PII 감지 및 탈감 구현
1단계: 기본 정규식 기반 감지
import re
from typing import Dict, List, Tuple
from dataclasses import dataclass
from enum import Enum
class PIIType(Enum):
RESIDENT_REGISTRATION = "resident_registration"
CREDIT_CARD = "credit_card"
PHONE = "phone"
EMAIL = "email"
NAME = "name"
ADDRESS = "address"
BANK_ACCOUNT = "bank_account"
@dataclass
class PIIMatch:
pii_type: PIIType
original_value: str
start_index: int
end_index: int
confidence: float
class PIIDetector:
"""한국어 PII 감지 및 탈감을 위한 기본 클래스"""
# 한국 기반 PII 패턴 정의
PATTERNS: Dict[PIIType, Tuple[str, float]] = {
PIIType.RESIDENT_REGISTRATION: (
r"\d{6}-[1-4]\d{6}",
0.95
),
PIIType.CREDIT_CARD: (
r"\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}",
0.98
),
PIIType.PHONE: (
r"01[016789][-\s]?\d{3,4}[-\s]?\d{4}",
0.92
),
PIIType.EMAIL: (
r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}",
0.95
),
PIIType.BANK_ACCOUNT: (
r"\d{3}-?\d{3}-?\d{6}",
0.88
),
}
# 이름 데이터베이스 (범용 한국 성씨 + 이름)
COMMON_KOREAN_SURNAMES = {
"김", "이", "박", "최", "정", "강", "조", "윤", "장", "임",
"한", "오", "서", "신", "권", "황", "안", "송", "류", "전"
}
def detect(self, text: str) -> List[PIIMatch]:
"""텍스트에서 PII 검색"""
matches = []
for pii_type, (pattern, confidence) in self.PATTERNS.items():
for match in re.finditer(pattern, text):
matches.append(PIIMatch(
pii_type=pii_type,
original_value=match.group(),
start_index=match.start(),
end_index=match.end(),
confidence=confidence
))
# Confidence 기준 정렬
matches.sort(key=lambda x: x.confidence, reverse=True)
return matches
def mask(self, text: str, matches: List[PIIMatch]) -> str:
"""감지된 PII 마스킹"""
result = text
offset = 0
for match in matches:
mask_char = self._get_mask_char(match.pii_type)
masked = mask_char * len(match.original_value)
start = match.start_index + offset
end = match.end_index + offset
result = result[:start] + masked + result[end:]
offset += len(masked) - len(match.original_value)
return result
def _get_mask_char(self, pii_type: PIIType) -> str:
"""PII 유형별 마스킹 문자 반환"""
mask_map = {
PIIType.RESIDENT_REGISTRATION: "*",
PIIType.CREDIT_CARD: "#",
PIIType.PHONE: "*",
PIIType.EMAIL: "*",
PIIType.BANK_ACCOUNT: "#",
}
return mask_map.get(pii_type, "*")
사용 예시
detector = PIIDetector()
test_text = """
고객 정보如下:
이름: 김민수
주민등록번호: 950123-1234567
연락처: 010-1234-5678
이메일: [email protected]
카드정보: 4532-1234-5678-9012
"""
matches = detector.detect(test_text)
print("감지된 PII:")
for m in matches:
print(f" [{m.pii_type.value}] {m.original_value} (신뢰도: {m.confidence})")
sanitized = detector.mask(test_text, matches)
print("\n탈감 후 텍스트:")
print(sanitized)
2단계: HolySheep AI API와 통합
실무에서는 정규식만으로는 한계가 있습니다. HolySheep AI의 Claude 기반 PII 감지 기능을 활용하면 더 정확한 분석이 가능합니다:
import os
import json
import httpx
from typing import Optional, Dict, List
HolySheep AI API 설정
https://api.holysheep.ai/v1 (base_url)
가입: https://www.holysheep.ai/register
class HolySheepPIIAnalyzer:
"""HolySheep AI 기반 고급 PII 감지 및 탈감"""
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = "https://api.holysheep.ai/v1"
async def analyze_with_ai(
self,
text: str,
detection_level: str = "strict"
) -> Dict:
"""
HolySheep AI를 활용한 PII 분석
Args:
text: 분석할 텍스트
detection_level: 'strict', 'balanced', 'permissive'
"""
prompt = f"""다음 텍스트에서 모든 PII(개인정보)를 식별하고 탈감하세요.
검색해야 할 정보 유형:
1. 이름 (한국어, 영어)
2. 주민등록번호 (한국)
3. 여권번호, 운전면허번호
4. 신용카드번호, 계좌번호
5. 전화번호 (휴대전화, 일반전화)
6. 이메일 주소
7. physical 주소
8. 생년월일
9. 의료 정보, 진단명
10. 금융 정보
{detection_level} 모드로 분석:
- strict: 모든 가능한 PII 포함
- balanced: 명확한 PII만
- permissive: 높은 신뢰도만
응답 형식 (JSON):
{{
"detected_pii": [
{{
"type": "주민등록번호",
"value": "950123-1234567",
"start": 10,
"end": 21,
"confidence": 0.98
}}
],
"sanitized_text": "마스킹된 텍스트",
"risk_score": 0.85,
"recommendations": ["추가 보안 조치"]
}}
텍스트: {text}"""
async with httpx.AsyncClient(timeout=30.0) as client:
response = await client.post(
f"{self.base_url}/chat/completions",
headers={
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
},
json={
"model": "claude-sonnet-4-20250514",
"messages": [
{"role": "system", "content": "당신은 PII 감지 전문가입니다. 정확한 JSON 응답만 반환하세요."},
{"role": "user", "content": prompt}
],
"temperature": 0.1,
"max_tokens": 2000
}
)
if response.status_code == 401:
raise PermissionError(
"HolySheep API 키가 유효하지 않습니다. "
"https://www.holysheep.ai/register 에서 새 키를 발급하세요."
)
response.raise_for_status()
result = response.json()
# AI 응답 파싱
ai_content = result["choices"][0]["message"]["content"]
# JSON 추출 (마크다운 코드 블록 제거)
if "```json" in ai_content:
ai_content = ai_content.split("``json")[1].split("``")[0]
elif "```" in ai_content:
ai_content = ai_content.split("``")[1].split("``")[0]
return json.loads(ai_content.strip())
async def batch_analyze(
self,
texts: List[str],
detection_level: str = "strict"
) -> List[Dict]:
"""배치 처리로 여러 텍스트 동시 분석"""
import asyncio
tasks = [
self.analyze_with_ai(text, detection_level)
for text in texts
]
return await asyncio.gather(*tasks)
사용 예시
async def main():
# HolySheep AI 키 설정
api_key = os.environ.get("HOLYSHEEP_API_KEY", "YOUR_HOLYSHEEP_API_KEY")
analyzer = HolySheepPIIAnalyzer(api_key)
# 분석할 텍스트
user_data = """
=== 고객 정보 ===
성명: 김영희
주민등록번호: 870105-2345678
연락처: 010-9876-5432
이메일: [email protected]
주소: 부산광역시 해운대구 우동 1234번지
=== 결제 정보 ===
카드번호: 5123-4567-8901-2345
유효기간: 12/28
"""
try:
result = await analyzer.analyze_with_ai(user_data, "strict")
print("=== PII 감지 결과 ===")
print(f"위험 점수: {result['risk_score']}")
print(f"\n감지된 PII 수: {len(result['detected_pii'])}")
for pii in result['detected_pii']:
print(f" - {pii['type']}: {pii['value']} "
f"(신뢰도: {pii['confidence']:.0%})")
print(f"\n=== 탈감 후 텍스트 ===")
print(result['sanitized_text'])
print(f"\n=== 권장 조치 ===")
for rec in result['recommendations']:
print(f" • {rec}")
except PermissionError as e:
print(f"인증 오류: {e}")
except httpx.TimeoutException:
print("HolySheep API 응답 시간 초과. 다시 시도하세요.")
except Exception as e:
print(f"예상치 못한 오류: {e}")
if __name__ == "__main__":
import asyncio
asyncio.run(main())
웹 서비스에 통합하기
Flask 기반 웹 서비스에서 PII 보호 미들웨어를 구현하는 실전 예제입니다:
from flask import Flask, request, jsonify
from functools import wraps
import logging
app = Flask(__name__)
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
PII 감지 인스턴스 (정규식 기반)
pii_detector = PIIDetector()
HolySheep AI 분석기 (고급)
class PIIProtectionMiddleware:
"""Flask 요청/응답 PII 보호 미들웨어"""
def __init__(self, app, holy_sheep_key: Optional[str] = None):
self.app = app
self.holy_sheep_analyzer = None
if holy_sheep_key:
self.holy_sheep_analyzer = HolySheepPIIAnalyzer(holy_sheep_key)
self._install_middleware()
def _install_middleware(self):
"""before_request/after_request 훅 등록"""
@self.app.before_request
def preprocess_request():
# 요청 데이터에서 PII 감지
if request.is_json:
data = request.get_json()
if data:
request.pii_analysis = self._analyze_data(data)
@self.app.after_request
def postprocess_response(response):
# 응답 로깅 시 PII 마스킹
if hasattr(request, 'pii_analysis'):
risk_level = request.pii_analysis.get('risk_score', 0)
# 위험도가 높으면 경고 로깅
if risk_level > 0.7:
logger.warning(
f"High PII risk detected in request. "
f"Risk score: {risk_level}",
extra={"sanitized": True}
)
return response
def _analyze_data(self, data):
"""요청 데이터 분석"""
text_content = self._flatten_to_text(data)
if self.holy_sheep_analyzer:
# HolySheep AI 활용 (실시간은 비용이 발생하므로 주석)
# return await self.holy_sheep_analyzer.analyze_with_ai(text_content)
pass
# 기본 정규식 분석
matches = pii_detector.detect(text_content)
return {
"pii_count": len(matches),
"pii_types": [m.pii_type.value for m in matches],
"sanitized": pii_detector.mask(text_content, matches)
}
def _flatten_to_text(self, obj) -> str:
"""중첩 객체를 문자열로 변환"""
if isinstance(obj, dict):
return " ".join(self._flatten_to_text(v) for v in obj.values())
elif isinstance(obj, list):
return " ".join(self._flatten_to_text(v) for v in obj)
elif isinstance(obj, str):
return obj
return str(obj)
미들웨어 초기화
HolySheep 가입: https://www.holysheep.ai/register
PIIProtectionMiddleware(app, holy_sheep_key=os.environ.get("HOLYSHEEP_API_KEY"))
@app.route("/api/user/support-ticket", methods=["POST"])
def create_support_ticket():
"""
고객 지원 티켓 생성 API
- 입력 데이터 자동 PII 감지
- AI 처리 전 민감 정보 보호
"""
data = request.get_json()
# 티켓 내용에 PII 분석 결과 첨부
analysis = getattr(request, 'pii_analysis', {})
if analysis.get('pii_count', 0) > 0:
logger.info(
f"Support ticket contains {analysis['pii_count']} PII items. "
f"Types: {analysis['pii_types']}"
)
# PII가 포함된 티켓은 별도 보안 처리
return jsonify({
"ticket_id": generate_ticket_id(),
"status": "requires_review",
"pii_notice": "민감 정보가 감지되었습니다. 수동 검토 후 처리됩니다.",
"analysis": analysis
}), 202
# PII 없음 - 즉시 처리
return jsonify({
"ticket_id": generate_ticket_id(),
"status": "created"
}), 201
@app.route("/api/ai/process", methods=["POST"])
def ai_process():
"""
AI 처리 전용 엔드포인트
- HolySheep AI Gateway를 통한 안전한 데이터 전송
"""
data = request.get_json()
user_message = data.get("message", "")
# PII 감지
matches = pii_detector.detect(user_message)
if matches:
# 원본 메시지를 HolySheep API에 보내지 않고 탈감 처리
sanitized_message = pii_detector.mask(user_message, matches)
# HolySheep AI Gateway로 전송
# base_url: https://api.holysheep.ai/v1
# model: claude-sonnet-4-20250514
return jsonify({
"ai_response": "고객님의 요청을 확인했습니다. "
f"요청에서 {len(matches)}개의 민감 정보가 자동으로 "
"보호处理되었습니다.",
"processing_note": "PII protection enabled",
"pii_masked": True
})
# PII 없음 - 정상 처리
return jsonify({
"ai_response": "요청을 처리합니다.",
"pii_masked": False
})
def generate_ticket_id() -> str:
import uuid
return f"TKT-{uuid.uuid4().hex[:8].upper()}"
if __name__ == "__main__":
app.run(debug=True, port=5000)
자주 발생하는 오류와 해결책
1. HolySheep API 401 Unauthorized 오류
❌ 잘못된 접근
api.openai.com 또는 api.anthropic.com 직접 호출 시
response = requests.post(
"https://api.anthropic.com/v1/messages",
headers={"x-api-key": "sk-ant-..."}
)
결과: 401 Unauthorized
✅ 올바른 접근 - HolySheep Gateway 사용
base_url은 반드시 https://api.holysheep.ai/v1
response = requests.post(
"https://api.holysheep.ai/v1/chat/completions",
headers={
"Authorization": f"Bearer {os.environ.get('HOLYSHEEP_API_KEY')}",
"Content-Type": "application/json"
},
json={
"model": "claude-sonnet-4-20250514",
"messages": [{"role": "user", "content": "분석 요청"}]
}
)
해결 방법
1. HolySheep Dashboard에서 API 키 재발급
2. 환경 변수에 올바른 키 설정 확인
3. 키가 유효期内인지 확인
2. PII 감지 누락 - 정규식 한계
❌ 정규식만으로는 감지 불가능한 사례
text = """
제 이름은 김철수입니다.
현금으로 5만 원 받고 계좌에 입금해주세요.
제 계좌는 국민은행 123-456-789 이고요.
"""
단순 정규식: 계좌번호 형식만 탐지
하지만 "현금으로 5만 원" 같은 암시적 금융 정보 누락
✅ 해결: HolySheep AI 기반 컨텍스트 인식
async def enhanced_detection(text: str, api_key: str):
analyzer = HolySheepPIIAnalyzer(api_key)
result = await analyzer.analyze_with_ai(text, "strict")
# 다음과 같은隐含적 정보도 감지:
# - 금융 거래 관련 금액 언급
# - 계좌 정보 암시적 표현
# - 의료 정보 contextual mention
return result
# HolySheep AI가 문맥을 이해하여 누락 최소화
3. 마스킹 후 텍스트 길이 불일치
❌ 길이 기반 단순 치환의 문제
def naive_mask(text, pattern, mask_char="#"):
matches = list(re.finditer(pattern, text))
# 뒤에서부터 처리하지 않으면 인덱스 오류
for match in reversed(matches):
# 인덱스 계산 오류 가능
pass
✅ 올바른 오프셋 기반 마스킹
def correct_mask(text: str, matches: List[PIIMatch]) -> str:
"""오프셋을 고려한 정확한 마스킹"""
result = text
offset = 0
# 인덱스 기준 정렬 (앞쪽 먼저 처리)
for match in sorted(matches, key=lambda x: x.start_index):
# 오프셋 누적 계산
start = match.start_index + offset
end = match.end_index + offset
mask = match.masked_value
result = result[:start] + mask + result[end:]
# 치환 후 길이 차이만큼 오프셋 업데이트
offset += len(mask) - len(match.original_value)
return result
✅ 오버랩 방지 처리
def mask_non_overlapping(text: str, matches: List[PIIMatch]) -> str:
"""오버랩되는 PII 먼저 병합 후 마스킹"""
# Confidence 높은 것 우선 정렬
sorted_matches = sorted(matches, key=lambda x: -x.confidence)
non_overlapping = []
for match in sorted_matches:
overlaps = False
for existing in non_overlapping:
if (match.start_index < existing.end_index and
match.end_index > existing.start_index):
overlaps = True
break
if not overlaps:
non_overlapping.append(match)
return correct_mask(text, non_overlapping)
4. 다국어 PII 감지 실패
❌ 한국어 패턴만 정의 시
PATTERNS = {
"phone_kr": r"01[0-9]-\d{3,4}-\d{4}",
# 영어 이름, 중국어 이름 등 누락
}
✅ 다국어 지원 확장
MULTILINGUAL_PATTERNS = {
# 한국
"phone_kr": r"01[016789][-\s]?\d{3,4}[-\s]?\d{4}",
"name_kr": r"[김이박최정강조윤장임한]|...",
# 영어 (글로벌)
"name_en": r"\b([A-Z][a-z]+\s?){1,3}\b",
"ssn_us": r"\d{3}-\d{2}-\d{4}",
"phone_us": r"\(\d{3}\)\s?\d{3}[-\s]?\d{4}",
# 중국어 이름 (간체/번체 혼재 방지)
"name_zh_simple": r"[\u4e00-\u9fa5]{2,4}", # 한자 2-4자
# 일본어
"name_jp": r"[ぁ-んァ-ン一-龯]{2,4}",
}
HolySheep AI를 활용한 자동 언어 감지
async def detect_language_and_pii(text: str, api_key: str):
analyzer = HolySheepPIIAnalyzer(api_key)
result = await analyzer.analyze_with_ai(
f"다국어 PII 감지를 수행하세요. 언어:auto, 텍스트:{text}"
)
return result
기업 환경용 완전한 솔루션
대규모 데이터 처리에는 HolySheep AI의 배치 처리 기능과 결합된 Kafka 또는 Redis 기반 실시간 파이프라인이 필요합니다:
docker-compose.yml (프로덕션 인프라)
version: '3.8'
services:
pii-processor:
build: ./pii-service
environment:
HOLYSHEEP_API_KEY: ${HOLYSHEEP_API_KEY}
REDIS_URL: redis://pii-redis:6379
KAFKA_BROKERS: pii-kafka:9092
depends_on:
- pii-redis
- pii-kafka
pii-redis:
image: redis:7-alpine
volumes:
- redis-data:/data
pii-kafka:
image: confluentinc/cp-kafka:7.4.0
environment:
KAFKA_ZOOKEEPER_CONNECT: pii-zookeeper:2181
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://pii-kafka:9092
Kubernetes Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: pii-protection-service
spec:
replicas: 3
selector:
matchLabels:
app: pii-protection
template:
metadata:
labels:
app: pii-protection
spec:
containers:
- name: pii-processor
image: myregistry/pii-service:v1.2.0
env:
- name: HOLYSHEEP_API_KEY
valueFrom:
secretKeyRef:
name: holy-sheep-credentials
key: api-key
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 8080
모범 사례 및 체크리스트
- 입력 검증: 모든 사용자 입력을 PII 감지 파이프라인에 통과시키기
- 최소 권한: API 키는 필요한 권한만 부여하고 정기적으로 교체
- 로그 마스킹: 애플리케이션 로깅 시 PII 자동 마스킹 활성화
- 감사 추적: PII 접근 및 처리 내역 완벽 기록
- 데이터 보존: 탈감 데이터와 원본 데이터 분리 저장 정책
- 침입 사고 대응: PII 유출 시 즉각 알림 및 대응 계획 수립
.env.production 설정
HOLYSHEEP_API_KEY=hs_live_your_api_key_here
PII_DETECTION_MODE=strict
PII_LOG_ENABLED=true
PII_AUDIT_TRAIL=true
PII_MASK_CHAR=*
PII_MAX_REQUESTS_PER_MINUTE=100
결론
PII 데이터 탈감은 AI 서비스 개발에서 선택이 아닌 필수입니다. HolySheep AI 게이트웨이를 활용하면 단일 API 키로 다양한 AI 모델의 강력한 PII 감지 기능을安全하게利用할 수 있습니다.
정규식 기반 기본 감지부터 HolySheep AI의 문맥 인식 분석까지, 요구사항에 맞는 적합한 레이어를 조합하여 개인정보 보호와 AI 서비스 품질을 동시에 달성하세요.
👉
HolySheep AI 가입하고 무료 크레딧 받기