개인정보자기결정권
자신의 개인정보 처리에 관해 스스로 결정할 수 있는 권리
자신의 개인정보 처리에 관해 스스로 결정할 수 있는 권리
개인정보자기결정권(Right to Informational Self-Determination)은 자신의 개인정보가 언제, 어디서, 어떻게 수집되고 처리되는지 스스로 결정할 수 있는 기본권입니다. GDPR에서는 이를 구체화하여 정보주체의 권리(Chapter III, Article 12-23)로 규정하고 있습니다.
GDPR이 보장하는 정보주체 권리는 1) 정보를 받을 권리(Article 13-14), 2) 열람권(Article 15), 3) 정정권(Article 16), 4) 삭제권/잊힐 권리(Article 17), 5) 처리제한권(Article 18), 6) 이동권(Article 20), 7) 반대권(Article 21), 8) 자동화 의사결정 관련 권리(Article 22)입니다.
AI 시스템에서 특히 중요한 것은 Article 22의 '프로파일링을 포함한 자동화된 개인 의사결정에 관한 권리'입니다. 정보주체는 법적 효과나 중대한 영향을 미치는 순수 자동화 의사결정의 적용을 받지 않을 권리가 있습니다.
한국 헌법재판소도 2005년 개인정보자기결정권을 헌법상 기본권으로 인정했으며, 개인정보보호법 제4조에서 정보주체의 권리를 명시하고 있습니다.
# 정보주체 권리 행사 관리 시스템 (DSR - Data Subject Request)
from dataclasses import dataclass, field
from typing import List, Dict, Optional
from datetime import datetime, timedelta
from enum import Enum
import json
class DSRType(Enum):
"""정보주체 권리 유형 (GDPR Chapter III)"""
ACCESS = "access" # 열람권 - Article 15
RECTIFICATION = "rectification" # 정정권 - Article 16
ERASURE = "erasure" # 삭제권 - Article 17
RESTRICTION = "restriction" # 처리제한권 - Article 18
PORTABILITY = "portability" # 이동권 - Article 20
OBJECTION = "objection" # 반대권 - Article 21
AUTOMATED_DECISION = "automated" # 자동화 의사결정 권리 - Article 22
class DSRStatus(Enum):
RECEIVED = "received"
IDENTITY_VERIFIED = "identity_verified"
IN_PROGRESS = "in_progress"
COMPLETED = "completed"
REJECTED = "rejected"
EXTENDED = "extended"
@dataclass
class DataSubjectRequest:
"""정보주체 권리 요청"""
id: str
request_type: DSRType
data_subject_id: str
email: str
received_at: datetime
details: str
status: DSRStatus = DSRStatus.RECEIVED
deadline: datetime = None
extended: bool = False
rejection_reason: Optional[str] = None
response: Optional[Dict] = None
def __post_init__(self):
# GDPR Article 12: 1개월 내 응답 의무
self.deadline = self.received_at + timedelta(days=30)
def extend_deadline(self, reason: str):
"""복잡한 요청 시 2개월 연장 (총 3개월)"""
if not self.extended:
self.deadline = self.received_at + timedelta(days=90)
self.extended = True
self.status = DSRStatus.EXTENDED
return {"extended": True, "new_deadline": self.deadline, "reason": reason}
raise ValueError("이미 연장된 요청입니다")
@dataclass
class DSRHandler:
"""정보주체 권리 요청 처리기"""
organization: str
requests: List[DataSubjectRequest] = field(default_factory=list)
# Article 17 삭제 예외 사유
ERASURE_EXCEPTIONS = [
"freedom_of_expression", # 표현의 자유
"legal_obligation", # 법적 의무
"public_interest_health", # 공중보건 공익
"archiving_purposes", # 기록보존 목적
"legal_claims", # 법적 청구권 행사/방어
]
def submit_request(self, request: DataSubjectRequest) -> Dict:
"""권리 요청 접수"""
self.requests.append(request)
return {
"request_id": request.id,
"type": request.request_type.value,
"received": request.received_at.isoformat(),
"deadline": request.deadline.isoformat(),
"message": f"요청이 접수되었습니다. {request.deadline.strftime('%Y-%m-%d')}까지 응답드리겠습니다."
}
def handle_access_request(self, request_id: str, user_data: Dict) -> Dict:
"""열람권 처리 (Article 15)"""
request = self._get_request(request_id)
request.status = DSRStatus.IN_PROGRESS
# Article 15에 따른 필수 제공 정보
response = {
"request_id": request_id,
"data_subject": request.data_subject_id,
"processing_purposes": user_data.get("purposes", []),
"categories_of_data": list(user_data.get("data", {}).keys()),
"recipients": user_data.get("recipients", []),
"retention_period": user_data.get("retention", "처리 목적 달성 시까지"),
"data_source": user_data.get("source", "정보주체 직접 제공"),
"automated_decision_making": user_data.get("automated_decision", False),
"rights_information": {
"rectification": "부정확한 정보 정정 요청 가능",
"erasure": "일정 조건 하에 삭제 요청 가능",
"restriction": "처리 제한 요청 가능",
"objection": "처리에 반대할 권리",
"portability": "기계판독 가능 형식으로 데이터 수령 가능",
"complaint": "감독기관에 민원 제기 가능"
},
"personal_data_copy": user_data.get("data", {})
}
request.response = response
request.status = DSRStatus.COMPLETED
return response
def handle_erasure_request(self, request_id: str, check_exceptions: bool = True) -> Dict:
"""삭제권/잊힐 권리 처리 (Article 17)"""
request = self._get_request(request_id)
request.status = DSRStatus.IN_PROGRESS
if check_exceptions:
# 삭제 예외 사유 확인 필요
exception_check = {
"legal_obligation": self._check_legal_retention(request.data_subject_id),
"legal_claims": self._check_ongoing_disputes(request.data_subject_id),
}
if any(exception_check.values()):
blocking_exceptions = [k for k, v in exception_check.items() if v]
request.status = DSRStatus.REJECTED
request.rejection_reason = f"삭제 예외 사유 해당: {blocking_exceptions}"
return {
"request_id": request_id,
"granted": False,
"reason": request.rejection_reason,
"legal_basis": "GDPR Article 17(3)"
}
# 삭제 수행
deletion_result = self._perform_deletion(request.data_subject_id)
request.status = DSRStatus.COMPLETED
request.response = deletion_result
return {
"request_id": request_id,
"granted": True,
"deleted_systems": deletion_result["systems"],
"deletion_date": datetime.now().isoformat(),
"note": "백업 데이터는 보관 정책에 따라 90일 후 자동 삭제됩니다."
}
def handle_portability_request(self, request_id: str, user_data: Dict, format: str = "json") -> Dict:
"""이동권 처리 (Article 20)"""
request = self._get_request(request_id)
# 기계판독 가능한 구조화된 형식으로 제공
portable_data = {
"export_date": datetime.now().isoformat(),
"data_subject": request.data_subject_id,
"format": format,
"data": user_data
}
if format == "json":
export = json.dumps(portable_data, ensure_ascii=False, indent=2)
else:
# CSV 등 다른 형식 지원 가능
export = portable_data
request.status = DSRStatus.COMPLETED
return {
"request_id": request_id,
"format": format,
"download_link": f"/api/dsr/{request_id}/download",
"expires_in": "7일"
}
def handle_automated_decision_request(self, request_id: str, decision_info: Dict) -> Dict:
"""자동화 의사결정 관련 권리 (Article 22)"""
request = self._get_request(request_id)
response = {
"request_id": request_id,
"automated_processing": True,
"logic_involved": decision_info.get("logic", "기계학습 기반 점수 산정"),
"significance": decision_info.get("significance", "서비스 제공 여부 결정에 영향"),
"envisaged_consequences": decision_info.get("consequences", []),
"human_review_available": True,
"how_to_request_review": "고객센터를 통해 인간 검토를 요청하실 수 있습니다.",
"right_to_contest": "결정에 이의를 제기하실 권리가 있습니다."
}
request.status = DSRStatus.COMPLETED
request.response = response
return response
def _get_request(self, request_id: str) -> DataSubjectRequest:
for req in self.requests:
if req.id == request_id:
return req
raise ValueError(f"요청을 찾을 수 없습니다: {request_id}")
def _check_legal_retention(self, user_id: str) -> bool:
# 법적 보관 의무 확인 로직
return False
def _check_ongoing_disputes(self, user_id: str) -> bool:
# 진행 중인 분쟁 확인 로직
return False
def _perform_deletion(self, user_id: str) -> Dict:
# 실제 삭제 수행 로직
return {"systems": ["main_db", "analytics", "crm"], "records_deleted": 150}
# 사용 예시
handler = DSRHandler(organization="KAITRUST Corp")
# 열람 요청 접수
access_request = DataSubjectRequest(
id="DSR-2024-001",
request_type=DSRType.ACCESS,
data_subject_id="USER-12345",
email="user@example.com",
received_at=datetime.now(),
details="보유 중인 모든 개인정보 열람 요청"
)
result = handler.submit_request(access_request)
print(f"접수 완료: {result['message']}")
DPO: "이번 달 DSR이 50건 넘었어요. 특히 AI 추천 관련 Article 22 요청이 많아졌습니다. 알고리즘 설명 템플릿 준비해 주세요."
개발팀: "의미있는 로직 설명이 핵심이죠. 어떤 피처가 결정에 영향을 미쳤는지 SHAP 값 기반으로 설명 생성하는 API 만들겠습니다."
면접관: "AI 시스템에서 개인정보자기결정권이 중요한 이유는?"
지원자: "AI의 자동화 의사결정이 개인에게 법적 효과나 중대한 영향을 미칠 수 있기 때문입니다. GDPR Article 22는 정보주체가 순수 자동화 결정을 거부할 권리, 인간 개입을 요청할 권리, 의미있는 설명을 받을 권리를 보장합니다. 이를 구현하려면 XAI(설명가능 AI) 기술이 필수입니다."
DPO: "이동권 API에서 데이터 포맷이 JSON만 지원되네요. CSV도 추가해야 정보주체가 다른 서비스로 쉽게 이전할 수 있어요."
개발자: "Article 20 취지가 상호운용성이니까 맞습니다. CSV, XML 포맷 추가하고, 응답 헤더에 Content-Disposition 설정해서 바로 다운로드되게 하겠습니다."