アプリケーション脆弱性診断基準ガイドライン
目的
本ドキュメントは、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, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/\//g, '/');
}
// 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-origin6. 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-devDAST(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=high2. 手動診断手法
ペネトレーションテスト
- 認証バイパステスト: トークン操作、セッション固定化
- インジェクション攻撃: SQL, NoSQL, Command Injection
- ビジネスロジック脆弱性: 医療ワークフローの悪用可能性
コードレビュー
- セキュリティフォーカスレビュー: 認証・認可、データバリデーション
- 暗号化実装レビュー: 暗号化キー管理、アルゴリズム選択
- エラーハンドリングレビュー: 情報漏洩防止
脆弱性対応プロセス
1. 発見・トリアージ
2. 緊急対応手順(Critical)
- 即座の隔離: 影響サービスの一時停止・アクセス制限
- ステークホルダー通知: CTO、医療責任者、法務チーム、セキュリティチームへの報告
- 緊急パッチ適用: ホットフィックスの開発・適用
- 影響範囲調査: ログ分析、データ整合性確認
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()報告・改善プロセス
脆弱性報告書
エグゼクティブサマリー
- 全体セキュリティ状況
- 医療コンプライアンス準拠状況
- 重要な推奨事項
技術詳細
- 各サービスの脆弱性詳細
- 修正の技術的手順
- 実装タイムライン
コンプライアンス評価
- 医療法規制への準拠状況
- 個人情報保護法への準拠状況
- 国際標準(ISO27001等)への準拠状況
継続的改善
- 四半期レビュー: セキュリティプロセスの改善
- 年次監査: 外部監査機関による包括評価
- インシデント後改善: 発生したセキュリティ事案からの学習
関連ドキュメント
更新履歴
- 2025-08-15: 初版作成
- 定期見直し: 四半期ごと
承認者: SREチーム、セキュリティチーム、医療情報管理責任者
次回見直し予定: 20xx-xx-xx