1. 医療向けのデータ分類フレームワーク

###1.1.データを分類する必要があるのはなぜですか?
すべてのデータに同じレベルの保護が必要なわけではありません。データ分類は次のことに役立ちます。
- セキュリティ コストの最適化: リソースを最も重要なデータに集中させます
- 法的遵守: 規制要件に従って正しい管理を適用します。
- 攻撃対象領域を削減: 機密データの範囲を制限します
- インシデント対応: 侵害が発生した場合の対処を優先します。
###1.2.医療データの分類レベル

| レベル | 名前 | 例 | 暗号化 | アクセス | 監査 |
|---|---|---|---|---|---|
| 4 - 制限付き | 最大制限 | HIV/エイズ、メンタルヘルス、遺伝学、依存症治療、リプロダクティブ・ヘルス | 必須 (AES-256) | 指名された個人のみ | 完全なログ記録、リアルタイムのアラート |
| 3 - 機密 | セキュリティ | カルテ、検査、処方箋、画像診断、健康保険 | 必須 (AES-256) | 役割ベース(治療臨床医) | 完全なログ |
| 2 - 内部 | 内部 | 予約スケジュール、統計 (匿名)、医療スタッフ、構成 | おすすめ | 部門別 | 標準ロギング |
| 1 - パブリック | パブリック | サービス、勤務時間、病院の連絡先、健康上の指示のリスト | 不要 | パブリック | 基本的なロギング |
###1.3. PostgreSQL スキーマにおけるデータ分類
-- Data classification metadata table
CREATE TABLE data_classification (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
schema_name VARCHAR(100) NOT NULL,
table_name VARCHAR(100) NOT NULL,
column_name VARCHAR(100) NOT NULL,
classification_level INTEGER NOT NULL CHECK (classification_level BETWEEN 1 AND 4),
classification_label VARCHAR(50) NOT NULL,
contains_phi BOOLEAN DEFAULT false,
encryption_required BOOLEAN DEFAULT false,
masking_rule VARCHAR(100),
retention_days INTEGER,
legal_basis TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Ví dụ classification cho patient table
INSERT INTO data_classification (schema_name, table_name, column_name,
classification_level, classification_label, contains_phi, encryption_required, masking_rule)
VALUES
('public', 'patients', 'id', 2, 'INTERNAL', false, false, NULL),
('public', 'patients', 'full_name', 3, 'CONFIDENTIAL', true, true, 'PARTIAL_MASK'),
('public', 'patients', 'date_of_birth', 3, 'CONFIDENTIAL', true, false, 'YEAR_ONLY'),
('public', 'patients', 'cccd_number', 3, 'CONFIDENTIAL', true, true, 'FULL_MASK'),
('public', 'patients', 'phone', 3, 'CONFIDENTIAL', true, true, 'PARTIAL_MASK'),
('public', 'patients', 'email', 3, 'CONFIDENTIAL', true, true, 'PARTIAL_MASK'),
('public', 'patients', 'address', 3, 'CONFIDENTIAL', true, true, 'CITY_ONLY'),
('public', 'patients', 'blood_type', 2, 'INTERNAL', false, false, NULL),
('public', 'patients', 'hiv_status', 4, 'RESTRICTED', true, true, 'FULL_MASK'),
('public', 'patients', 'insurance_number', 3, 'CONFIDENTIAL', true, true, 'PARTIAL_MASK');
2. データ フロー マッピング
###2.1.マイクロサービスにおける PHI データ フロー

###2.2.データ フロー ドキュメント テンプレート
| # | データ要素 | 出典 | 目的地 | 交通機関 | 暗号化 | 分類 |
|---|---|---|---|---|---|---|
| 1 | 患者名 | ポータル | 患者サービス | HTTPS/TLS 1.3 | 輸送中 + 静止中 | L3 |
| 2 | ラボの結果 | 実験器具 | ラボサービス | TLS 上の HL7v2/MLLP | 輸送中 + 静止中 | L3 |
| 3 | 診断コード | 臨床サービス | 請求サービス | カフカ (SSL) | アプリケーションレベル | L3 |
| 4 | HIV ステータス | 臨床サービス | 臨床DB | JDBC/SSL | 列の暗号化 | L4 |
| 5 | 監査イベント | すべてのサービス | 監査サービス | カフカ (SSL) | イベントの暗号化 | L2 |
| 6 | 予約 | スケジューリングサービス | 通知サービス | カフカ (SSL) | 輸送中 | L2 |
3. NIST SP 800-30 に基づくリスク評価
###3.1.リスク評価方法

###3.2.医療マイクロサービスの脅威の特定
| 脅威カテゴリ | 脅威 | 脅威の発生源 |
|---|---|---|
| 外部 | 患者サービスへの SQL インジェクション | 攻撃者 |
| 外部 | ランサムウェアはデータベースを暗号化します | サイバー犯罪 |
| 外部 | API 呼び出しに対する MITM 攻撃 | ネットワーク攻撃 |
| 外部 | 患者ポータルへの資格情報の詰め込み | ボットネットワーク |
| 内部 | 従業員による PHI への不正アクセス | インサイダー |
| 内部 | データベース管理者はすべての患者データをエクスポートします | 特権ユーザー |
| 内部 | 開発者のハードコード資格情報 | 怠慢な従業員 |
| 環境 | ハードウェア障害によるデータベースの破損 | インフラ |
| 環境 | 自然災害によるデータ損失 | 自然災害 |
| サプライチェーン | Quarkus 依存関係の脆弱性 | サードパーティ |
###3.3.脆弱性評価
// Ví dụ: Checklist kiểm tra vulnerabilities trong Quarkus service
public class SecurityVulnerabilityChecklist {
// V1: SQL Injection - Sử dụng parameterized queries
// ❌ VULNERABLE
String badQuery = "SELECT * FROM patients WHERE name = '" + userInput + "'";
// ✅ SECURE
@NamedQuery(name = "Patient.findByName",
query = "SELECT p FROM Patient p WHERE p.name = :name")
List<Patient> findByName(@Param("name") String name);
// V2: Broken Authentication - Token validation
// ❌ VULNERABLE: Không verify token
String userId = jwt.getClaim("sub"); // Không verify expiration, issuer
// ✅ SECURE: Quarkus OIDC tự động verify
@Authenticated
@RolesAllowed("doctor")
public Response getPatient(UUID id) { ... }
// V3: Sensitive Data Exposure in Logs
// ❌ VULNERABLE
log.info("Patient created: " + patient.toString()); // Logs PHI!
// ✅ SECURE
log.info("Patient created: id={}", patient.getId()); // Only log ID
}
###3.4.リスクマトリクス

| 無視できる (1) | 低 (2) | 中 (3) | 高 (4) | クリティカル (5) | |
|---|---|---|---|---|---|
| 非常に高い (5) | 低い | 中 | 高い | クリティカル | クリティカル |
| 高 (4) | 低い | 中 | 高い | 高い | クリティカル |
| 中 (3) | 低い | 低い | 中 | 高い | 高い |
| 低 (2) | 低い | 低い | 低い | 中 | 中 |
| 非常に低い (1) | 低い | 低い | 低い | 低い | 中 |
4. 医療マイクロサービスのリスク登録
###4.1.リスク登録テンプレート
| ID | リスクの説明 | 可能性 | 影響 | リスクレベル | 緩和 | オーナー | ステータス |
|---|---|---|---|---|---|---|---|
| R001 | 患者 API への SQL インジェクション | 中 (3) | クリティカル (5) | 高い | パラメータ化されたクエリ、入力検証、WAF | 開発チーム | 緩和 |
| R002 | インサイダー アクセス PHI は許可されていません | 高 (4) | 高 (4) | 高い | RBAC、RLS、監査ログ、DLP | セキュリティチーム | 進行中 |
| R003 | ランサムウェアは、patient_db を暗号化します。中 (3) | クリティカル (5) | 高い | 不変バックアップ、ネットワークセグメンテーション、EDR | 運用チーム | 緩和 | |
| R004 | Keycloakトークンの盗難 | 中 (3) | 高 (4) | 高い | 有効期間の短いトークン、mTLS、DPoP | 開発チーム | 進行中 |
| R005 | ログ内の PHI 暴露 | 高 (4) | 高 (4) | 高い | ログのサニタイズ、CI/CD での PHI 検出 | 開発チーム | 開く |
| R006 | Kafka の暗号化されていない PHI | 中 (3) | 高 (4) | 高い | アプリケーションレベルの暗号化、Kafka SSL | 開発チーム | 開く |
| R007 | データベースのバックアップの盗難 | 低 (2) | クリティカル (5) | 中 | 暗号化されたバックアップ、キー管理 | 運用チーム | 緩和 |
| R008 | API キー/認証情報の公開 | 中 (3) | 高 (4) | 高い | Vault シークレット管理、ハードコーディングされたシークレットなし | すべてのチーム | 進行中 |
| R009 | 患者ポータルでの DDoS | 中 (3) | 中 (3) | 中 | レート制限、WAF、CDN | 運用チーム | 緩和 |
| R010 | サードパーティの依存関係 CVE | 高 (4) | 中 (3) | 高い | 自動スキャン、Dependabot、SBOM | 開発チーム | 継続中 |
###4.2.リスク治療計画

- 軽減 ← リスクが高い場合に推奨: コントロールを実装し、可能性/影響を軽減します。
- TRANSFER (転送): サイバー保険、専門プロバイダーへのアウトソーシング
- ACCEPT (受け入れる) ← 低リスクの場合のみ: リスク受容の文書化、モニタリング
- AVOID (回避): リスク源を排除し、アーキテクチャを変更します。
5. データ保持ポリシー
###5.1.ベトナムの健康に関する保持要件
| データ型 | 保管時間 | 法的根拠 |
|---|---|---|
| 外来診療記録 | 10年 | 回覧 46/2018/TT-BYT |
| 入院患者の医療記録 | 20年 | 回覧 46/2018/TT-BYT |
| 死亡医療記録 | 20年 | 回覧 46/2018/TT-BYT |
| テスト結果 | 10年 | 病院の規則 |
| 画像診断 | 10年 | 病院の規則 |
| 監査ログ | 6 年 (HIPAA) | HIPAA §164.530(j) |
| 処方箋 | 5年 | 薬事法 |
| 同意記録 | 生涯 + 6 年 | HIPAA / 政令 13/2023 |
###5.2. PostgreSQL での自動保存
-- Partition strategy for data retention
CREATE TABLE audit_events (
id UUID DEFAULT gen_random_uuid(),
event_time TIMESTAMPTZ NOT NULL DEFAULT NOW(),
event_type VARCHAR(50) NOT NULL,
actor_id UUID NOT NULL,
resource_type VARCHAR(100) NOT NULL,
resource_id UUID,
action VARCHAR(20) NOT NULL,
outcome VARCHAR(20) NOT NULL,
details JSONB
) PARTITION BY RANGE (event_time);
-- Create monthly partitions
CREATE TABLE audit_events_2026_01 PARTITION OF audit_events
FOR VALUES FROM ('2026-01-01') TO ('2026-02-01');
CREATE TABLE audit_events_2026_02 PARTITION OF audit_events
FOR VALUES FROM ('2026-02-01') TO ('2026-03-01');
-- Automated partition management
-- Drop partitions older than retention period (6 years for HIPAA)
-- Archive to cold storage before dropping
6. まとめ
このレッスンでは次のことを行います。
- 医療データのための 4 レベルの データ分類フレームワーク を開発する
- マイクロサービス アーキテクチャ経由で PHI の データ フロー マッピング を作成
- NIST SP 800-30 方法論に従って リスク評価 を実行します
- リスク治療計画を含む リスク登録 を設定します
- ベトナムの規制および HIPAA に基づく データ保持ポリシー の定義
演習
- 医療システム データベース内のすべてのテーブル/列を 4 つのレベルに分類します。
- 3 つの主な使用例のデータ フロー図を作成します: 検査への登録、検査結果の記録、薬の処方
- リスク評価を実行し、少なくとも 15 個のリスクについてリスク登録を作成します
- 組織に適したデータ保持ポリシーを策定する
| ◀ 前の記事 | 次の記事 ▶ |
|---|---|
| レッスン 2: Quarkus Stack を使用した医療向けの安全なマイクロサービス アーキテクチャ | レッスン 4: 医療情報システムの STRIDE/DREAD の脅威モデリング |