제6장

보안 및 암호화 검증

6.1 디지털 서명 체계

디지털 서명은 공공문서의 진위성, 무결성, 부인 방지를 보장하는 핵심 메커니즘입니다. WIA-SOCIAL은 RSA, ECDSA, EdDSA 등 다양한 서명 알고리즘을 지원하며, 각 문서 유형과 보안 요구사항에 따라 적절한 알고리즘을 선택할 수 있습니다.

지원 서명 알고리즘

알고리즘 키 크기 보안 강도 성능 권장 용도
RSA-SHA256 2048-4096 bit 높음 느림 여권, 출생증명서 등 장기 보관 문서
ECDSA P-256 256 bit 높음 빠름 운전면허증, 일반 행정 문서
EdDSA (Ed25519) 256 bit 매우 높음 매우 빠름 실시간 검증이 필요한 모바일 문서
RSA-PSS 2048-4096 bit 매우 높음 느림 국가 중요 문서, 법적 계약서

디지털 서명 생성 및 검증 (Node.js)

import crypto from 'crypto';
import fs from 'fs';

class DocumentSigner {
  private privateKey: crypto.KeyObject;
  private publicKey: crypto.KeyObject;

  constructor(privateKeyPath: string, publicKeyPath: string) {
    this.privateKey = crypto.createPrivateKey(
      fs.readFileSync(privateKeyPath, 'utf8')
    );
    this.publicKey = crypto.createPublicKey(
      fs.readFileSync(publicKeyPath, 'utf8')
    );
  }

  signDocument(documentData: any): string {
    // 문서를 정규화된 JSON으로 변환 (순서 보장)
    const canonicalJson = JSON.stringify(documentData, Object.keys(documentData).sort());

    // SHA-256 해시 생성
    const hash = crypto.createHash('sha256').update(canonicalJson).digest();

    // RSA-SHA256 서명 생성
    const signature = crypto.sign('sha256', hash, {
      key: this.privateKey,
      padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
      saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST
    });

    return signature.toString('base64');
  }

  verifySignature(documentData: any, signature: string): boolean {
    const canonicalJson = JSON.stringify(documentData, Object.keys(documentData).sort());
    const hash = crypto.createHash('sha256').update(canonicalJson).digest();

    const signatureBuffer = Buffer.from(signature, 'base64');

    try {
      return crypto.verify(
        'sha256',
        hash,
        {
          key: this.publicKey,
          padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
          saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST
        },
        signatureBuffer
      );
    } catch (error) {
      return false;
    }
  }

  // 타임스탬프 포함 서명 (RFC 3161)
  signWithTimestamp(documentData: any, tsaUrl: string): {
    signature: string;
    timestamp: string;
    tsaSignature: string;
  } {
    const signature = this.signDocument(documentData);
    const timestamp = new Date().toISOString();

    // TSA (Time Stamping Authority)에 타임스탬프 요청
    // 실제 구현에서는 TSA 서버와 통신
    const tsaSignature = this.requestTimestamp(signature, tsaUrl);

    return { signature, timestamp, tsaSignature };
  }

  private requestTimestamp(signature: string, tsaUrl: string): string {
    // RFC 3161 타임스탬프 요청 구현
    // 여기서는 간략화
    return 'tsa_signature_placeholder';
  }
}

// 사용 예시
const signer = new DocumentSigner(
  '/path/to/private_key.pem',
  '/path/to/public_key.pem'
);

const birthCertificate = {
  documentId: 'WIA-DOC-2025-0123456789',
  documentType: 'BIRTH_CERTIFICATE',
  fullName: '홍길동',
  dateOfBirth: '2025-01-10',
  issuingAuthority: 'Seoul City Government'
};

// 서명 생성
const signature = signer.signDocument(birthCertificate);
console.log('서명:', signature);

// 서명 검증
const isValid = signer.verifySignature(birthCertificate, signature);
console.log('서명 유효:', isValid);

6.2 공개 키 인프라 (PKI)

PKI는 디지털 인증서를 발급, 관리, 폐기하는 시스템입니다. WIA-SOCIAL PKI는 계층적 인증 기관 구조를 사용하여 신뢰 체인을 구축합니다.

PKI 계층 구조

Root CA (최상위 인증 기관)
 ├─ WIA Root Certificate Authority
 │
 ├─ Intermediate CA Level 1 (국가별)
 │   ├─ Korea CA
 │   ├─ Singapore CA
 │   └─ Estonia CA
 │
 └─ Intermediate CA Level 2 (기관별)
     ├─ Seoul City Government CA
     ├─ Busan City Government CA
     └─ Ministry of Interior CA
         │
         └─ End Entity Certificates (실제 서명 인증서)
             ├─ Officer Kim (발급 담당자)
             ├─ Officer Lee (검증 담당자)
             └─ System Certificate (자동화 시스템)

인증서 발급 및 관리

인증서 유형 유효 기간 갱신 주기 사용 목적
Root CA 20년 거의 안 함 최상위 신뢰 앵커
Intermediate CA 10년 5년마다 하위 CA 서명
End Entity (발급 담당자) 2년 1년마다 문서 서명
End Entity (시스템) 1년 6개월마다 자동화 서명
시민 인증서 3년 2년마다 문서 접근 및 검증

6.3 암호화 및 키 관리

민감한 개인 정보를 포함하는 공공문서는 저장 및 전송 시 암호화되어야 합니다. WIA-SOCIAL은 AES-256-GCM을 사용한 대칭 암호화와 RSA/ECDH를 사용한 비대칭 암호화를 결합합니다.

하이브리드 암호화 구현

import crypto from 'crypto';

class DocumentEncryption {
  // 문서 암호화 (하이브리드 방식)
  encryptDocument(
    documentData: any,
    recipientPublicKey: crypto.KeyObject
  ): {
    encryptedData: string;
    encryptedKey: string;
    iv: string;
    authTag: string;
  } {
    // 1. AES-256-GCM 대칭 키 생성 (랜덤)
    const aesKey = crypto.randomBytes(32); // 256 bits
    const iv = crypto.randomBytes(12); // 96 bits (GCM 권장)

    // 2. 문서를 AES-256-GCM으로 암호화
    const cipher = crypto.createCipheriv('aes-256-gcm', aesKey, iv);
    const documentJson = JSON.stringify(documentData);

    let encryptedData = cipher.update(documentJson, 'utf8', 'base64');
    encryptedData += cipher.final('base64');

    const authTag = cipher.getAuthTag();

    // 3. AES 키를 수신자의 공개 키로 RSA 암호화
    const encryptedKey = crypto.publicEncrypt(
      {
        key: recipientPublicKey,
        padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
        oaepHash: 'sha256'
      },
      aesKey
    );

    return {
      encryptedData,
      encryptedKey: encryptedKey.toString('base64'),
      iv: iv.toString('base64'),
      authTag: authTag.toString('base64')
    };
  }

  // 문서 복호화
  decryptDocument(
    encryptedData: string,
    encryptedKey: string,
    iv: string,
    authTag: string,
    privateKey: crypto.KeyObject
  ): any {
    // 1. RSA 개인 키로 AES 키 복호화
    const aesKey = crypto.privateDecrypt(
      {
        key: privateKey,
        padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
        oaepHash: 'sha256'
      },
      Buffer.from(encryptedKey, 'base64')
    );

    // 2. AES-256-GCM으로 문서 복호화
    const decipher = crypto.createDecipheriv(
      'aes-256-gcm',
      aesKey,
      Buffer.from(iv, 'base64')
    );

    decipher.setAuthTag(Buffer.from(authTag, 'base64'));

    let decryptedData = decipher.update(encryptedData, 'base64', 'utf8');
    decryptedData += decipher.final('utf8');

    return JSON.parse(decryptedData);
  }

  // 필드 수준 암호화 (특정 필드만 암호화)
  encryptSensitiveFields(
    documentData: any,
    sensitiveFields: string[],
    key: Buffer
  ): any {
    const result = { ...documentData };

    sensitiveFields.forEach(field => {
      if (result[field]) {
        const iv = crypto.randomBytes(12);
        const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);

        let encrypted = cipher.update(
          JSON.stringify(result[field]),
          'utf8',
          'base64'
        );
        encrypted += cipher.final('base64');

        result[field] = {
          encrypted: true,
          data: encrypted,
          iv: iv.toString('base64'),
          authTag: cipher.getAuthTag().toString('base64')
        };
      }
    });

    return result;
  }
}

// 사용 예시
const encryption = new DocumentEncryption();

// 수신자의 공개 키 로드
const recipientPublicKey = crypto.createPublicKey(
  fs.readFileSync('/path/to/recipient_public_key.pem')
);

const document = {
  documentId: 'WIA-DOC-2025-0123456789',
  fullName: '홍길동',
  nationalID: '900520-1234567',
  address: '서울시 강남구 테헤란로 123'
};

// 문서 암호화
const encrypted = encryption.encryptDocument(document, recipientPublicKey);

// 복호화 (수신자 측)
const recipientPrivateKey = crypto.createPrivateKey(
  fs.readFileSync('/path/to/recipient_private_key.pem')
);

const decrypted = encryption.decryptDocument(
  encrypted.encryptedData,
  encrypted.encryptedKey,
  encrypted.iv,
  encrypted.authTag,
  recipientPrivateKey
);

6.4 접근 제어 및 권한 관리

공공문서는 엄격한 접근 제어가 필요합니다. WIA-SOCIAL은 역할 기반 접근 제어(RBAC)와 속성 기반 접근 제어(ABAC)를 결합한 하이브리드 모델을 사용합니다.

접근 제어 정책

문서 유형 소유자 권한 가족 권한 정부 기관 권한 제3자 권한
출생증명서 읽기, 공유 읽기 (부모/보호자) 읽기, 수정, 취소 읽기 (승인 시)
운전면허증 읽기, 갱신 없음 읽기, 수정, 정지 검증만
여권 읽기 없음 읽기, 발급, 취소 검증만
재산 증서 읽기, 이전 읽기 (배우자) 읽기, 등기 검증만

6.5 GDPR 및 개인정보 보호

WIA-SOCIAL은 GDPR, CCPA 등 국제 개인정보 보호 규정을 준수합니다. 주요 준수 사항은 다음과 같습니다.

🔒 개인정보 보호 원칙

6.6 보안 감사 및 모니터링

모든 문서 접근 및 수정 활동은 감사 로그에 기록되며, 이상 행위 탐지 시스템이 실시간으로 모니터링합니다.

감사 로그 예시

{
  "auditId": "AUDIT-2025-01-15-ABC123",
  "timestamp": "2025-01-15T10:30:00.123Z",
  "eventType": "DOCUMENT_ACCESSED",
  "actor": {
    "userId": "user-123456",
    "name": "김철수",
    "role": "CITIZEN",
    "ipAddress": "203.0.113.42",
    "userAgent": "Mozilla/5.0...",
    "location": {
      "country": "KR",
      "city": "Seoul"
    }
  },
  "resource": {
    "documentId": "WIA-DOC-2025-0123456789",
    "documentType": "BIRTH_CERTIFICATE",
    "owner": "홍길동"
  },
  "action": "READ",
  "result": "SUCCESS",
  "accessMethod": "WEB_PORTAL",
  "authenticationMethod": "TWO_FACTOR",
  "sessionId": "sess-789012",
  "riskScore": 0.1,
  "anomalyDetected": false
}

요약

공공문서 시스템의 보안은 디지털 서명, PKI, 암호화, 접근 제어, 개인정보 보호, 감사 추적이 통합된 다계층 방어 체계로 구성됩니다. 이러한 보안 메커니즘은 문서의 진위성과 무결성을 보장하고, 개인정보를 보호하며, 법적 요구사항을 충족합니다. 다음 장에서는 실제 시스템 통합 및 배포 전략을 살펴봅니다.

🤔 복습 질문

  1. RSA-SHA256과 ECDSA P-256의 차이점과 각각의 사용 사례를 설명하세요.
  2. PKI의 인증서 체인이 어떻게 신뢰를 구축하는지 설명하세요.
  3. 하이브리드 암호화가 순수 비대칭 암호화보다 효율적인 이유는 무엇인가요?
  4. RBAC와 ABAC의 차이점을 설명하고, 공공문서 시스템에서 어떻게 활용되는지 논의하세요.
  5. GDPR의 '잊힐 권리'를 공공문서 시스템에서 어떻게 구현할 수 있나요?