⚖️ AI 규제/윤리

개인정보자기결정권

자신의 개인정보 처리에 관해 스스로 결정할 수 있는 권리

상세 설명

개인정보자기결정권(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 설정해서 바로 다운로드되게 하겠습니다."

주의사항

더 배우기