Skip to content

セキュリティ

本システムは保険業務の特性上、個人情報 および 要配慮個人情報(健康情報・マイナンバー等)を扱う前提で設計する。技術的安全管理措置を 多層防御 で実装する。

守る対象(資産)

区分機密度
認証情報パスワードハッシュ、セッション、TOTPシード最大
外部API資格情報LINE Channel Token、Google Refresh Token、Stripe/Square API Key最大
要配慮個人情報健康情報、マイナンバー、身分証番号最大
個人情報氏名、住所、電話、メール、生年月日
業務情報契約内容、保険金額、商品
ファイル証券スキャン、申込書、本人確認書類区分による
業務ログアクティビティ、スケジュール
メタ情報テナント設定、ユーザー設定

脅威モデル(簡易 STRIDE)

脅威主な対策
Spoofing なりすまし強パスワード + TOTP MFA、セッション固定対策、CSRF
Tampering 改ざんTLS / HSTS、Webhook 署名検証、入力検証、監査ログ
Repudiation 否認監査ログ(break-glass にも対応)、操作の actor / IP 記録
Information Disclosure 情報漏えいエンベロープ暗号、テナント分離、PIIマスキング、最小権限
Denial of Serviceレート制限、Cloudflare WAF、Workers のスケール
Elevation of Privilege 権限昇格二重認可(MW + サービス層)、ADMIN分離、break-glass 監査

暗号化アーキテクチャ

全体像(エンベロープ暗号化)

  • KEK (Key Encryption Key): 全テナント共通のマスタ鍵。Cloudflare Workers Secrets で保管。
  • DEK (Data Encryption Key): テナント単位の対称鍵。tenants.dek_enc に KEK で暗号化して保存。
  • 暗号化カラム / 高機密ファイルは テナントの DEK で暗号化。
  • リクエスト処理時に DEK を復号してメモリに展開、レスポンス後に破棄。

アルゴリズム

  • 対称暗号: AES-256-GCM(WebCrypto API)
  • ハッシュ: SHA-256
  • パスワード: Better Auth のデフォルト(Argon2id 推奨)
  • 乱数: crypto.getRandomValues

鍵ローテーション

周期手順
KEK年次 + 漏えい疑義時新KEK生成 → 全テナントの dek_enc を再暗号化 → 旧KEK失効
DEKテナント要求時 / 漏えい疑義時新DEK生成 → 既存暗号化カラムを再暗号化 → 旧DEK失効
TOTPシードユーザー操作時のみリセット時に再生成
API キー(外部連携)推奨6か月各プロバイダの手順に従う

暗号化対象一覧(コード命名規則: *_enc

場所カラム内容
tenantsdek_encテナント DEK 自身KEK
line_channelschannel_secret_enc, access_token_encLINE 資格情報テナントDEK
external_calendar_linksrefresh_token_encGoogle OAuthテナントDEK
payment_provider_settings (ADMIN管理)api_key_enc, webhook_secret_encStripe/SquareKEK 直下(システム層)
customerssensitive_data_enc(要配慮 JSON)健康情報、マイナンバー等テナントDEK
customer_identifiersvalue_enc身分証番号、銀行口座末尾テナントDEK
webhook_eventspayload_enc(任意)機微なペイロードテナントDEK

ファイル暗号化(R2)

機密区分

区分既定保管プレビューサムネイル署名URL有効期限
publicR2 SSE60分
internalR2 SSE30分
confidentialR2 SSE5分
sensitiveR2 SSE + アプリ層 AES-GCM (テナントDEK)❌(原寸のみDL)2分

高機密ファイルのアップロード / ダウンロード

  • 高機密ファイルは 直アップロードしない(暗号化のため Worker を経由)
  • ダウンロードもプロキシ経由。署名URL直接配布は使わない
  • LINE 受信添付ファイルは「internal 既定」で取り込み、ユーザーが昇格できる

認証

パスワードポリシー

  • 最低12文字、英大小+数字+記号のうち3種以上
  • 既知漏洩パスワード辞書(HIBP API)と照合(任意)
  • 履歴: 直近5世代と同一不可(後続)

TOTP (MFA)

  • OWNER / ADMIN は MFA 必須
  • MEMBER は任意(テナント設定で必須化可能)
  • リカバリーコード(10個)を発行、ハッシュ保存
  • 端末紛失時のリセットは ADMIN 申請+本人確認

セッション

  • Cookie: HttpOnly / Secure / SameSite=Lax
  • 既定有効期限 8時間(業務時間想定)。OWNER/ADMIN は 4時間に短縮(テナント設定)
  • アイドルタイムアウト 60分(無操作で再認証)
  • 同時セッション: 端末別に許可、OWNER/ADMIN 画面で一覧と失効が可能
  • 不審な IP / UA 変化検知でメール通知(後続)

失敗ロックアウト

  • 同一アカウントで連続失敗 5回 → 15分ロック(指数バックオフ後続)
  • ADMIN 操作で即時解除可能

認可(多層)

  • テナント越境はミドルウェア + サービス層で二重チェック
  • 要配慮情報の閲覧は 追加権限(OWNER の許可リストに登録された MEMBER のみ)
  • break-glass: 例外的アクセス時には「理由」入力を必須化し、監査ログに残す

監査ログ

必須記録対象

  • 認証成功 / 失敗 / MFA / ロックアウト
  • ロール変更 / 権限変更 / メンバー招待・削除
  • 要配慮データの閲覧 / 編集 / エクスポート
  • ファイルのダウンロード(特に confidential / sensitive
  • 暗号化キー操作(KEK / DEK の生成・ローテーション)
  • ADMIN によるテナント横断操作 すべて
  • 設定変更(決済プロバイダ、LINE チャネル接続、外部連携)

スキーマ(暫定)

ts
audit_logs {
  id: ulid (PK)
  tenant_id: string | null  // ADMIN 操作は null
  actor_user_id: string
  actor_role: 'OWNER' | 'MEMBER' | 'ADMIN'
  action: string  // 'customer.read_sensitive' 等
  target_type: string  // 'customer' / 'file' / 'tenant'
  target_id: string
  reason: string | null  // break-glass 時
  ip: string
  user_agent: string
  occurred_at: datetime
  prev_hash: string  // 前レコードのhash
  hash: string  // 自レコードのhash
}

改ざん耐性

  • append-only(更新・削除SQLを禁止、運用上は ADMIN でも不可)
  • 各行に前行ハッシュを含めてハッシュチェイン化(後続実装)
  • 一定間隔で外部ログ基盤(Logpush + R2 / 外部DWH)にエクスポート

ロギングと PII マスキング

  • アプリログには PII を出さない:
    • 氏名、電話、メール、住所、生年月日 → マスクまたは ID 参照
    • エラーメッセージにDBの値をそのまま入れない
  • リクエストログ: メソッド / パス / ステータス / 所要時間 / ユーザーID / テナントID / リクエストID
  • ボディは原則ログしない。問題調査時は機密区分を判定して短時間のサンプル取得

通信路

  • TLS 1.2+ 強制(Cloudflare 側で終端)
  • HSTS 有効化
  • 重要 Cookie: Secure HttpOnly SameSite=Lax
  • Webhook: 必ず署名検証(LINE / Stripe / Square / Google)
  • CORS: 同一オリジン以外の API 直叩きは原則拒否、ADMIN ツール用は明示許可リスト

レート制限と濫用対策

  • 認証エンドポイント: IP + アカウントの両軸で制限
  • 一斉配信 / エクスポート: テナント単位のクォータ
  • LINE Webhook: チャネル単位の流入制限 + キュー
  • ADMIN エンドポイント: 別レート(厳しめ)

バックアップと復旧

  • D1 のバックアップ: Cloudflare 機能 + 日次論理ダンプを R2 別バケットへ
  • バックアップは 暗号化された状態のまま保管
  • 復旧テストを四半期に1回(後続運用)
  • DEK のリストア: KEK で dek_enc を復号できるかを定期検証

データ保持と削除

  • ソフトデリート(deleted_at)→ 一定期間後に物理削除
  • 保険業法・APPI に基づく保管期間 を検討:
    • 顧客同意・苦情記録は所定の期間保管
    • 期間経過後は安全な方法で削除(暗号化キー破棄による無効化も選択肢)
  • ユーザー / テナントの削除リクエスト対応:
    • 30日以内に削除完了
    • 法令上保管必須のデータは仮名化して残す

脆弱性管理

  • 依存ライブラリの定期更新(Dependabot / Renovate 後続)
  • 既知CVEの監視
  • 重要ライブラリ(Better Auth、Hono、Drizzle、Mermaid 等)はメジャー更新前にレビュー
  • 静的解析(ESLint セキュリティルール、gitleaks 等)を CI に組込
  • ペネトレーションテスト: ローンチ前 + 年次(後続)

インシデント対応

  • 検知: 異常なログイン、データ大量取得、暗号化キー操作、外部からの脆弱性報告
  • 封じ込め: 該当セッション失効、テナントロック、外部連携停止
  • 調査: 監査ログ + アクセスログ + サーバログ
  • 通知: 個人情報漏えい時は APPI 第26条 に基づく報告 / 本人通知
  • 是正: 該当 DEK のローテーション、必要なら KEK ローテーション、再発防止

開発・運用ガバナンス

  • 本番アクセスは ADMIN のみ、操作はすべて監査
  • 開発環境では本番データを使わない(合成データ、もしくは仮名化)
  • 秘密情報は Workers Secrets / 環境変数のみ。コード・ログ・PR に露出させない
  • コードレビュー必須、セキュリティに関わる変更は必ずタグ付け
  • リリース前のチェックリスト(暗号化要件、監査要件、入力検証)

チェックリスト

  • 暗号化対象カラムをすべて *_enc
  • 暗号化抽象 (EncryptionService
  • gitleaks

未確定

  • 顧客マイナンバーの取得すべきかどうか