LESSON 40分

ストーリー

高橋アーキテクト
暗号化の技術は分かった。でも、全てのデータを同じレベルで暗号化する必要はあるか?

高橋アーキテクトがデータの一覧を広げました。

高橋アーキテクト
ユーザーの”お気に入り色”とクレジットカード番号を同じレベルで保護する必要はない。データを重要度で分類し、それぞれに適切な保護を適用するのが効率的だ

データ分類レベル

レベル名称説明
Level 1公開公開されても問題ないデータ公開プロフィール、商品情報
Level 2内部社内利用のデータ社内文書、会議メモ
Level 3機密漏洩すると損害が発生するデータ個人情報、顧客リスト
Level 4最高機密漏洩すると重大な損害が発生するデータクレジットカード、医療情報

データ分類マトリクス

// データ分類の定義
interface DataClassification {
  field: string;
  level: 1 | 2 | 3 | 4;
  encryptionAtRest: boolean;
  encryptionInTransit: boolean;
  masking: boolean;
  retentionDays: number;
  accessLog: boolean;
}

const userDataClassification: DataClassification[] = [
  {
    field: "userId",
    level: 1,
    encryptionAtRest: false,
    encryptionInTransit: true,
    masking: false,
    retentionDays: -1, // 無期限
    accessLog: false,
  },
  {
    field: "displayName",
    level: 1,
    encryptionAtRest: false,
    encryptionInTransit: true,
    masking: false,
    retentionDays: -1,
    accessLog: false,
  },
  {
    field: "email",
    level: 3,
    encryptionAtRest: true,
    encryptionInTransit: true,
    masking: true,    // 表示時: t***@example.com
    retentionDays: 365,
    accessLog: true,
  },
  {
    field: "phoneNumber",
    level: 3,
    encryptionAtRest: true,
    encryptionInTransit: true,
    masking: true,    // 表示時: ***-****-1234
    retentionDays: 365,
    accessLog: true,
  },
  {
    field: "creditCardNumber",
    level: 4,
    encryptionAtRest: true,
    encryptionInTransit: true,
    masking: true,    // 表示時: ****-****-****-1234
    retentionDays: 90,
    accessLog: true,
  },
  {
    field: "passwordHash",
    level: 4,
    encryptionAtRest: true,
    encryptionInTransit: true,
    masking: false,   // そもそも表示しない
    retentionDays: -1,
    accessLog: true,
  },
];

レベル別の保護策

保護策Level 1Level 2Level 3Level 4
通信時暗号化(TLS)oooo
保存時暗号化--oo
フィールドレベル暗号化---o
データマスキング--oo
アクセスログ--oo
バックアップ暗号化-ooo
自動削除--oo
DLP(情報漏洩防止)---o

データマスキングの実装

// データマスキングのユーティリティ
const maskingRules: Record<string, (value: string) => string> = {
  email: (email: string): string => {
    const [local, domain] = email.split("@");
    return `${local[0]}${"*".repeat(Math.max(local.length - 1, 2))}@${domain}`;
  },

  phone: (phone: string): string => {
    // 下4桁のみ表示: ***-****-1234
    return phone.replace(/\d(?=\d{4})/g, "*");
  },

  creditCard: (cc: string): string => {
    // 下4桁のみ表示: ****-****-****-1234
    return cc.replace(/\d(?=\d{4})/g, "*");
  },

  name: (name: string): string => {
    // 最初の1文字 + マスク: 田***
    return name[0] + "*".repeat(Math.max(name.length - 1, 2));
  },
};

// レスポンスのフィルタリング
const sanitizeResponse = (
  user: User,
  viewerRole: string,
): Partial<User> => {
  if (viewerRole === "admin") {
    // 管理者でもマスキング(生データは監査ログ経由でのみアクセス)
    return {
      ...user,
      email: maskingRules.email(user.email),
      phone: user.phone ? maskingRules.phone(user.phone) : undefined,
    };
  }

  // 一般ユーザーには最小限の情報のみ
  return {
    id: user.id,
    displayName: user.displayName,
    avatarUrl: user.avatarUrl,
  };
};

データライフサイクル管理

// データの保存期間と自動削除
interface RetentionPolicy {
  dataType: string;
  retentionDays: number;
  action: "delete" | "anonymize" | "archive";
}

const retentionPolicies: RetentionPolicy[] = [
  { dataType: "sessionLogs", retentionDays: 30, action: "delete" },
  { dataType: "accessLogs", retentionDays: 365, action: "archive" },
  { dataType: "paymentInfo", retentionDays: 90, action: "delete" },
  { dataType: "userProfiles", retentionDays: -1, action: "anonymize" },
  // userProfilesは退会時に匿名化
];

// 定期実行の削除ジョブ
const enforceRetention = async (): Promise<void> => {
  for (const policy of retentionPolicies) {
    if (policy.retentionDays < 0) continue;

    const cutoffDate = new Date();
    cutoffDate.setDate(cutoffDate.getDate() - policy.retentionDays);

    switch (policy.action) {
      case "delete":
        await db.query(
          `DELETE FROM ${policy.dataType} WHERE created_at < $1`,
          [cutoffDate],
        );
        break;
      case "anonymize":
        await db.query(
          `UPDATE ${policy.dataType} SET email = 'deleted', name = 'deleted' WHERE created_at < $1`,
          [cutoffDate],
        );
        break;
      case "archive":
        await archiveToS3(policy.dataType, cutoffDate);
        break;
    }
  }
};

まとめ

ポイント内容
データ分類4段階のレベルでデータを分類
レベル別保護重要度に応じた暗号化・マスキング
マスキング表示時に機密部分を隠す
ライフサイクル保存期間を定めて自動削除・匿名化

チェックリスト

  • データの4段階分類レベルを理解した
  • レベル別の保護策を把握した
  • データマスキングの実装方法を理解した
  • データライフサイクル管理の重要性を認識した

次のステップへ

次は「シークレット管理」を学びます。APIキー、パスワード、証明書などの機密情報を安全に管理する方法を身につけましょう。


推定読了時間: 40分