Skip to content

アプリケーション脆弱性診断基準ガイドライン

目的

本ドキュメントは、FastDoctorのアプリケーションレイヤーに対する脆弱性診断の基準と手順を定義します。医療・ヘルスケアプラットフォームとして、患者データの保護と医療情報システムの安全性を確保するため、包括的なアプリケーションセキュリティ診断を実施します。

適用範囲

  • 54のマイクロサービスアプリケーション(AI診断、電子カルテ、患者管理、医師支援等)
  • API Gateway、BFF(Backend for Frontend)、フロントエンドアプリケーション
  • コンテナ化されたアプリケーション(ECS Fargate)
  • サーバーレスアプリケーション(Lambda関数)
  • 静的サイト(CloudFront + S3)、WebSocket通信

医療・ヘルスケア特有のセキュリティ要件

コンプライアンス基準

  • 医療情報システム安全管理ガイドライン: 厚生労働省3省2ガイドライン準拠
  • 個人情報保護法: 要配慮個人情報(医療情報)の適切な取り扱い
  • 医療法: 医療記録の保存・管理要件
  • PCI DSS: 決済情報の保護(payment-service)
  • GDPR: 国際患者対応における個人データ保護

データ分類・取り扱い基準

【機密度レベル】
Level 1 (Critical): 患者の診療情報、処方箋データ、決済情報
Level 2 (High):     患者の個人情報、医師の診療記録、予約情報
Level 3 (Medium):   サービス利用履歴、統計データ(非特定)
Level 4 (Low):      公開情報、マーケティング情報

脆弱性診断分類・緊急度

Critical(緊急)- 24時間以内対応

  • SQLインジェクション: 患者データベースへの不正アクセス可能
  • 認証バイパス: 医師・患者アカウントの不正利用
  • 機密データ漏洩: 診療記録、個人情報の外部流出
  • RCE(Remote Code Execution): サーバー乗っ取り可能

High(高)- 1週間以内対応

  • XSS: 患者・医師の認証情報窃取可能
  • CSRF: 不正な医療記録変更・予約変更
  • 認証情報漏洩: パスワード、APIキーの平文保存
  • 権限昇格: 一般ユーザーから管理者権限への昇格

Medium(中)- 1ヶ月以内対応

  • 情報漏洩: 技術的詳細、エラーメッセージからの情報露出
  • セッション管理: セッションハイジャック、固定化攻撃
  • 入力値検証不備: DoS攻撃、データ改ざんの可能性
  • 暗号化不備: 弱い暗号化アルゴリズムの使用

Low(低)- 次回メンテナンス時対応

  • 情報開示: バージョン情報、ディレクトリ構造の露出
  • 設定不備: セキュリティヘッダーの未設定
  • ログ不備: セキュリティイベントの記録不足

サービス別脆弱性診断チェックリスト

1. 認証・認可システム

Cognito + API Gateway

  • [ ] 認証設定監査
javascript
// JWT トークン検証例
const jwt = require('jsonwebtoken');

function validateToken(token) {
    try {
        const decoded = jwt.verify(token, process.env.JWT_SECRET);
        // 有効期限チェック
        if (decoded.exp < Date.now() / 1000) {
            throw new Error('Token expired');
        }
        return decoded;
    } catch (error) {
        throw new Error('Invalid token');
    }
}
  • [ ] パスワード政策確認

    • 最小8文字、大文字・小文字・数字・記号の組み合わせ
    • パスワード履歴管理(過去12回分の再利用禁止)
    • アカウントロックアウト(5回失敗で30分ロック)
  • [ ] MFA(多要素認証)

    • SMS、TOTP、FIDO2対応確認
    • 医師アカウントのMFA必須化
    • バックアップコードの生成・管理
  • [ ] セッション管理

    • セッション有効期限(最大8時間)
    • アイドルタイムアウト(30分)
    • 同時セッション数制限

2. API セキュリティ

RESTful API診断

  • [ ] 入力値検証
python
# 入力値サニタイゼーション例
import re
from typing import Optional

def validate_patient_id(patient_id: str) -> Optional[str]:
    # 患者IDの形式チェック(英数字のみ、8-12文字)
    if re.match(r'^[A-Za-z0-9]{8,12}$', patient_id):
        return patient_id
    return None

def sanitize_medical_data(data: str) -> str:
    # HTMLタグの除去、SQLインジェクション対策
    cleaned = re.sub(r'<[^>]*>', '', data)
    cleaned = cleaned.replace("'", "''")  # SQLエスケープ
    return cleaned[:1000]  # 最大長制限
  • [ ] SQLインジェクション対策

    • パラメータ化クエリの使用確認
    • ORM(Object-Relational Mapping)の適切な使用
    • 動的SQL構築の監査
  • [ ] APIレート制限

yaml
# API Gateway設定例
throttle:
  rate_limit: 100    # 100 requests per second
  burst_limit: 200   # burst up to 200 requests
per_patient_limit: 10  # 患者1人あたり10リクエスト/分
  • [ ] レスポンス検証
    • エラーメッセージからの情報漏洩防止
    • スタックトレース非表示
    • 統一されたエラーレスポンス形式

GraphQL API診断(該当サービス)

  • [ ] クエリ深度制限
  • [ ] 複雑性スコア制限
  • [ ] イントロスペクション無効化(本番環境)

3. データ保護・暗号化

医療データハンドリング

  • [ ] 保存時暗号化
sql
-- Aurora MySQL暗号化確認
SELECT 
    table_schema,
    table_name,
    encryption
FROM information_schema.tables 
WHERE table_schema = 'healthcare_db';
  • [ ] 転送時暗号化

    • TLS 1.2以上の強制
    • HSTS(HTTP Strict Transport Security)設定
    • 証明書の有効性確認
  • [ ] アプリケーションレベル暗号化

javascript
// 機密医療情報の追加暗号化
const crypto = require('crypto');

function encryptMedicalData(data, key) {
    const cipher = crypto.createCipher('aes-256-gcm', key);
    const encrypted = cipher.update(data, 'utf8', 'hex') + cipher.final('hex');
    const authTag = cipher.getAuthTag();
    return {
        encrypted: encrypted,
        authTag: authTag.toString('hex')
    };
}
  • [ ] ログ出力監査
    • 患者ID、診断結果の非ログ出力確認
    • 構造化ログによる機密情報フィルタリング
    • ログローテーション・保持期間設定

4. 主要サービス個別診断

online-karte-service(電子カルテ)

  • [ ] 診療記録の整合性

    • データ改ざん検知メカニズム
    • 医師による電子署名検証
    • 診療記録の版管理・監査ログ
  • [ ] HL7 FHIR準拠

    • 医療情報交換標準への準拠確認
    • 外部システム連携時のデータ検証

ai-triage-service(AI診断支援)

  • [ ] AI結果の信頼性
python
# AI診断結果の検証例
def validate_ai_diagnosis(diagnosis_result):
    required_fields = ['confidence_score', 'diagnosis_code', 'recommendation']
    
    # 必須フィールドの存在確認
    for field in required_fields:
        if field not in diagnosis_result:
            raise ValueError(f"Missing required field: {field}")
    
    # 信頼度スコアの範囲確認
    confidence = diagnosis_result.get('confidence_score', 0)
    if not 0 <= confidence <= 1:
        raise ValueError("Invalid confidence score")
    
    return True
  • [ ] 説明可能AI
    • 診断根拠の提示機能
    • バイアス検出・軽減メカニズム
    • 人間の医師による最終判断プロセス

payment-service(決済サービス)

  • [ ] PCI DSS準拠

    • カード番号のトークン化
    • PCI DSS要件準拠の定期監査
    • 決済ログの適切な管理
  • [ ] 不正検知

    • 異常な決済パターンの検出
    • 地理的位置情報による不正検知
    • リアルタイム不正検知アラート

eligibility-verification(資格確認)

  • [ ] 外部連携セキュリティ
    • VPN接続の暗号化レベル確認
    • 外部システム認証の多要素化
    • 通信ログの監査

5. フロントエンドセキュリティ

SPA(Single Page Application)

  • [ ] XSS対策
javascript
// XSS対策の実装例
function sanitizeUserInput(input) {
    return input
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;')
        .replace(/'/g, '&#x27;')
        .replace(/\//g, '&#x2F;');
}

// CSP設定例
const cspPolicy = `
    default-src 'self';
    script-src 'self' 'unsafe-inline' https://apis.fastdoctor.com;
    style-src 'self' 'unsafe-inline';
    img-src 'self' data: https:;
    connect-src 'self' https://api.fastdoctor.com wss://websocket.fastdoctor.com;
`;
  • [ ] CSRF対策

    • CSRFトークンの生成・検証
    • SameSite Cookieの設定
    • Referrerチェック
  • [ ] セキュリティヘッダー

http
# 推奨セキュリティヘッダー
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Referrer-Policy: strict-origin-when-cross-origin

6. WebSocket通信セキュリティ

online-karte-websocket

  • [ ] WebSocket認証
javascript
// WebSocket認証実装例
const WebSocket = require('ws');

const wss = new WebSocket.Server({
    port: 8080,
    verifyClient: (info) => {
        const token = info.req.headers.authorization;
        return validateJWTToken(token);
    }
});

wss.on('connection', (ws, req) => {
    const userId = extractUserIdFromToken(req.headers.authorization);
    
    ws.on('message', (data) => {
        // メッセージの検証とサニタイゼーション
        const validatedData = validateAndSanitizeMessage(data, userId);
        if (validatedData) {
            // 処理実行
        }
    });
});
  • [ ] リアルタイム通信監査
    • メッセージの暗号化
    • 接続者の権限確認
    • 通信ログの記録

7. コンテナ・インフラストラクチャ診断

ECS Fargate セキュリティ

  • [ ] コンテナイメージ監査
dockerfile
# セキュアなDockerfile例
FROM node:18-alpine AS builder

# 非rootユーザーでの実行
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001

# 脆弱性スキャン対応
RUN apk update && apk upgrade
RUN npm audit --audit-level high

USER nextjs
EXPOSE 3000
  • [ ] ランタイムセキュリティ
    • 最小限の権限でのコンテナ実行
    • 読み取り専用ファイルシステム
    • セキュリティコンテキスト設定

Lambda関数セキュリティ

  • [ ] IAM権限最小化
json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:GetItem",
                "dynamodb:PutItem"
            ],
            "Resource": "arn:aws:dynamodb:region:account:table/patient-appointments"
        }
    ]
}
  • [ ] 環境変数管理
    • AWS Parameter Store使用
    • 機密情報の暗号化保存
    • ランタイム時の復号化

脆弱性診断ツールと手法

1. 自動化ツール

SAST(Static Application Security Testing)

bash
# SonarQubeを使用したコード解析
sonar-scanner \
    -Dsonar.projectKey=fastdoctor-services \
    -Dsonar.sources=. \
    -Dsonar.host.url=http://sonarqube:9000

# ESLintセキュリティルール
npm install eslint-plugin-security --save-dev

DAST(Dynamic Application Security Testing)

bash
# OWASP ZAP自動スキャン
zap-baseline.py -t https://api.fastdoctor.com -J zap-report.json

# Nmap脆弱性スキャン
nmap -sV --script vuln target-api.fastdoctor.com

依存関係スキャン

bash
# npm audit
npm audit --audit-level high

# Snyk脆弱性チェック
snyk test --severity-threshold=high

2. 手動診断手法

ペネトレーションテスト

  • 認証バイパステスト: トークン操作、セッション固定化
  • インジェクション攻撃: SQL, NoSQL, Command Injection
  • ビジネスロジック脆弱性: 医療ワークフローの悪用可能性

コードレビュー

  • セキュリティフォーカスレビュー: 認証・認可、データバリデーション
  • 暗号化実装レビュー: 暗号化キー管理、アルゴリズム選択
  • エラーハンドリングレビュー: 情報漏洩防止

脆弱性対応プロセス

1. 発見・トリアージ

2. 緊急対応手順(Critical)

  1. 即座の隔離: 影響サービスの一時停止・アクセス制限
  2. ステークホルダー通知: CTO、医療責任者、法務チーム、セキュリティチームへの報告
  3. 緊急パッチ適用: ホットフィックスの開発・適用
  4. 影響範囲調査: ログ分析、データ整合性確認

3. 修正・テスト

bash
# 修正後のリグレッションテスト
pytest tests/security/ -v --cov=src/

# 脆弱性修正の確認
zap-cli --zap-url http://zap:8080 spider http://localhost:3000
zap-cli --zap-url http://zap:8080 active-scan http://localhost:3000

診断スケジュール

定期診断

  • 毎週: 依存関係脆弱性スキャン
  • 月次: 自動SAST/DASTスキャン
  • 四半期: ペネトレーションテスト
  • 年次: 外部セキュリティ監査

継続的監視

  • リアルタイム: WAF、IDS/IPSによる攻撃検知
  • 日次: セキュリティログ分析
  • 週次: 異常パターン分析

セキュアコーディング基準

1. 入力値検証

typescript
// TypeScript入力値検証例
import joi from 'joi';

const patientSchema = joi.object({
    patientId: joi.string().alphanum().length(10).required(),
    name: joi.string().max(100).pattern(/^[a-zA-Z\s]+$/).required(),
    birthDate: joi.date().max('now').required(),
    medicalHistory: joi.string().max(5000).optional()
});

function validatePatientData(data: any) {
    const { error, value } = patientSchema.validate(data);
    if (error) {
        throw new ValidationError(error.details[0].message);
    }
    return value;
}

2. 安全なデータベースアクセス

javascript
// パラメータ化クエリの使用
const mysql = require('mysql2/promise');

async function getPatientRecord(patientId) {
    const query = 'SELECT * FROM patients WHERE patient_id = ? AND active = 1';
    const [rows] = await connection.execute(query, [patientId]);
    return rows;
}

// ORMを使用した安全なクエリ
const { Patient } = require('../models');

async function findPatientByIdSecure(patientId) {
    return await Patient.findOne({
        where: { 
            patient_id: patientId,
            active: true
        },
        attributes: { exclude: ['password_hash', 'ssn'] }
    });
}

3. 暗号化実装

python
# Python暗号化実装例
from cryptography.fernet import Fernet
import hashlib
import os

class MedicalDataCrypto:
    def __init__(self, key: bytes):
        self.fernet = Fernet(key)
    
    def encrypt_medical_data(self, data: str) -> str:
        return self.fernet.encrypt(data.encode()).decode()
    
    def decrypt_medical_data(self, encrypted_data: str) -> str:
        return self.fernet.decrypt(encrypted_data.encode()).decode()
    
    @staticmethod
    def hash_patient_id(patient_id: str, salt: bytes) -> str:
        return hashlib.pbkdf2_hmac('sha256', 
                                   patient_id.encode(), 
                                   salt, 
                                   100000).hex()

報告・改善プロセス

脆弱性報告書

  1. エグゼクティブサマリー

    • 全体セキュリティ状況
    • 医療コンプライアンス準拠状況
    • 重要な推奨事項
  2. 技術詳細

    • 各サービスの脆弱性詳細
    • 修正の技術的手順
    • 実装タイムライン
  3. コンプライアンス評価

    • 医療法規制への準拠状況
    • 個人情報保護法への準拠状況
    • 国際標準(ISO27001等)への準拠状況

継続的改善

  • 四半期レビュー: セキュリティプロセスの改善
  • 年次監査: 外部監査機関による包括評価
  • インシデント後改善: 発生したセキュリティ事案からの学習

関連ドキュメント


更新履歴

  • 2025-08-15: 初版作成
  • 定期見直し: 四半期ごと

承認者: SREチーム、セキュリティチーム、医療情報管理責任者
次回見直し予定: 20xx-xx-xx