Skip to content

セキュリティ設計

本ドキュメントは、TASHIKAプラットフォームのセキュリティアーキテクチャ設計を定義します。


認証アーキテクチャ

トークンベース認証

BFF Proxy パターン を採用し、トークン管理を BFF サーバーサイドに完全移行する。ブラウザには HttpOnly Session Cookie のみを渡し、JWT Access Token / Refresh Token はブラウザに一切露出しない。

→ BFF Proxy パターンの詳細設計: BFF 認証アーキテクチャ

トークン種別有効期間保存場所用途
Session Cookie7日ブラウザ(HttpOnly; Secure; SameSite=Strict)BFF セッションの識別
Access Token短命(15分)BFF サーバーサイドセッションApplication 層への認証(ステートレス検証)
Refresh Token長命(7日)BFF サーバーサイドセッション + サーバーDBAccess Tokenの再発行、セッション管理
ログインリクエスト認証 (credentials / OIDC)Access Token + Refresh Tokenトークンをサーバーサイド保存HttpOnly Session Cookie(Secure; SameSite=Strict)API リクエスト (Session Cookie)Access Token 取得API リクエスト (Bearer Token)レスポンスレスポンスRefresh Token 取得トークンリフレッシュ新 Access Token + Refresh Token新トークンを保存JWT はブラウザに露出しないAccess Token 期限切れ時ブラウザBFF ServerBFF セッションApplication APIIdP / 認証基盤
ログインリクエスト認証 (credentials / OIDC)Access Token + Refresh Tokenトークンをサーバーサイド保存HttpOnly Session Cookie(Secure; SameSite=Strict)API リクエスト (Session Cookie)Access Token 取得API リクエスト (Bearer Token)レスポンスレスポンスRefresh Token 取得トークンリフレッシュ新 Access Token + Refresh Token新トークンを保存JWT はブラウザに露出しないAccess Token 期限切れ時ブラウザBFF ServerBFF セッションApplication APIIdP / 認証基盤
  • ブラウザに JWT が存在しないため、XSS による Access Token 窃取リスクを排除
  • トークンリフレッシュは BFF 内部で自動実行され、ブラウザは関与しない
  • セッション管理(同時セッション数制限、強制ログアウト等)は BFF セッション + Refresh Token のサーバーサイド追跡で実現
  • SSO/OIDC(→ SR-012)の認証フローも BFF がリレーパーティとして処理し、IdP トークンはブラウザに露出しない(→ BFF 認証アーキテクチャ

→ 満たす要件: SR-002 認証要件

多要素認証 (MFA)

  • 管理者・代行事業者スタッフには TOTP による2要素認証を必須化
  • Authenticator アプリ互換(Google Authenticator, Microsoft Authenticator等)

→ 満たす要件: SR-003 MFA要件


認可アーキテクチャ

システムロールと業務ロールの対応

業務ロールはワークフロー上の役割、システムロールは認可(何にアクセスできるか)を制御する。同一のシステムロールを持つユーザーが、異なる業務ロールを担う場合がある。

業務ロールシステムロール備考
申告者employee
確認担当者tenant_admin / agency_staff組織モデルによる
責任者tenant_admin / agency_admin組織モデルによる
業務担当者tenant_admin代行モデルでも企業管理者が担う(連携結果の確認は確認担当者の業務範囲)
代行管理者agency_admin代行モデルのみ
企業管理者tenant_admin

→ 業務ロールの定義: アクターとロール

ポリシーベース認可

単なるロールだけでなく、クレームに基づくポリシーを適用:

ポリシー説明
TenantPolicyTenantId が一致しないデータへのアクセスをDBレベル(RLS)で遮断
AgencyPolicy顧問先横断アクセスの制御
ImpersonationPolicy代理ログイン時の個人情報マスキング、閲覧のみ許可
ExternalApiPolicyスコープに基づくAPIアクセス制御

Row Level Security (RLS)

  • PostgreSQL RLS + アプリケーション側の Global Query Filter を併用
  • 「アプリにバグがあっても他テナントデータは見えない」を構造的に保証

→ 満たす要件: SR-004 認可要件


セッション管理設計

項目設定
同時セッション数最大3デバイス(Refresh Tokenのサーバーサイド管理で制御)
アイドルタイムアウト30分
強制ログアウト管理者が実行可能(全デバイスのRefresh Tokenを即時無効化)
セッション一覧ユーザーが自分のアクティブセッションを確認・個別破棄可能

→ 満たす要件: SR-005 セキュリティポリシー要件


暗号化設計

データ暗号化

対象方式備考
マイナンバーAES-256 (アプリケーションレベル暗号化)DBには暗号文のみ保存。下4桁のみ平文で保持(検索用)
通信TLS 1.3HTTPS必須。TLS 1.2以下は拒否
バックアップAES-256本番とは異なる鍵で管理

鍵管理

HSM/KMS で鍵を保護し、アプリケーションコードから平文の鍵にアクセス不可とする。

鍵種別用途保護方式ローテーション方式
KEK (Key Encryption Key)DEK の暗号化KMS (HSM バック)年次自動KMS の自動ローテーション機能。旧バージョンは復号専用に保持
DEK (Data Encryption Key)マイナンバーの暗号化KEK で暗号化して DB 保存年次デュアルキー方式。新 DEK で再暗号化バッチを非同期実行
JWT 署名鍵Access Token の署名KMS (HSM バック)90日JWKS エンドポイントで公開鍵を配布。旧鍵は Access Token 有効期限(15分)+ バッファ後に無効化
DB 接続PostgreSQL 認証Workload Identity 推奨90日Workload Identity の場合はトークン自動更新。パスワード方式の場合はデュアルキー
TLS 証明書HTTPS 通信マネージド証明書自動更新ACME プロトコルによる自動更新

鍵ローテーション(デュアルキー方式):

DEK および DB 接続パスワードのローテーションにはデュアルキー方式を採用する。

新 DEK (v2) を生成DEK v1 (復号用) + DEK v2 (暗号化用)DEK v1 で暗号化されたデータを読み取りDEK v1 で復号 → DEK v2 で再暗号化DEK v2 で暗号化したデータを書き戻しDEK v1 を無効化新規書き込み → DEK v2 で暗号化読み取り → DEK v1 / v2 どちらでも復号可能Phase 2: 再暗号化バッチPhase 3: 旧鍵の無効化DEK v2 のみで運用運用担当Cloud KMSApplicationPostgreSQL
新 DEK (v2) を生成DEK v1 (復号用) + DEK v2 (暗号化用)DEK v1 で暗号化されたデータを読み取りDEK v1 で復号 → DEK v2 で再暗号化DEK v2 で暗号化したデータを書き戻しDEK v1 を無効化新規書き込み → DEK v2 で暗号化読み取り → DEK v1 / v2 どちらでも復号可能Phase 2: 再暗号化バッチPhase 3: 旧鍵の無効化DEK v2 のみで運用運用担当Cloud KMSApplicationPostgreSQL

緊急ローテーション:

鍵の漏洩が疑われる場合は、通常のデュアルキー並行運用期間を省略し、即時無効化 → 新鍵生成 → 再暗号化を実施する(→ SR-011 シークレット管理)。

→ 満たす要件: CR-009 暗号鍵管理SR-011 シークレット管理


API セキュリティ設計

通信セキュリティ

対策設定
HSTSmax-age=31536000; includeSubDomains
CSPdefault-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'
CORS許可オリジンをホワイトリストで管理
レート制限テナントごと 1,000 req/min(トークンバケット方式)

Webhook セキュリティ

  • HMAC-SHA256 署名をヘッダーに付与し、受信側で検証
  • ペイロードにマイナンバー等の機微情報を含めない

→ 満たす要件: SR-008 APIセキュリティ要件


ファイルセキュリティ設計

マルウェアスキャン

  • アップロードされた全ファイル(画像/PDF/XML)に対し、保存前に自動ウイルススキャンを実行
  • 感染ファイルの保存を防止

→ 満たす要件: SR-006 マルウェア対策要件


監査ログ設計

記録対象

  • 「いつ、誰が、どの従業員のデータを見た/変更したか」の完全な操作ログ
  • 代理ログイン時は「代行者」として明記
  • マイナンバーの閲覧は特に厳格に記録(→ CR-011 マイナンバー法対応

保存要件

  • 7年間保持(申告データと同期)
  • Write-Once ストレージで改ざん防止

テーブルスキーマ設計

DM-901 AuditLog の物理スキーマ:

カラムNULL説明
iduuid (ULID)NOT NULL主キー。時系列ソート可能な ULID
tenant_iduuidNOT NULLテナント ID(RLS フィルタ対象)
actor_iduuidNOT NULL操作を実行したユーザー ID
actor_roletextNOT NULL操作時のロール(employee, tenant_admin, agency_staff 等)
impersonated_byuuidNULL代理ログイン時の実行者 ID。直接操作時は NULL
actiontextNOT NULL操作種別(view, create, update, submit, approve, decrypt_mynumber 等)
resource_typetextNOT NULL対象リソース種別(declaration, employee, withholding_slip 等)
resource_iduuidNULL対象リソース ID。一覧表示等の場合は NULL
tax_yearintegerNULL対象年度。年度に紐づかない操作の場合は NULL
detailsjsonbNULL操作の詳細情報(変更前後の値等)。マイナンバー平文は絶対禁止
ip_addressinetNOT NULLクライアント IP アドレス
user_agenttextNULLクライアントの User-Agent
trace_idtextNOT NULL分散トレーシング用のトレース ID
created_attimestamptzNOT NULL記録日時(サーバー時刻)
checksumtextNOT NULLハッシュチェーン用の SHA-256 チェックサム

改ざん防止設計(3層防御)

Layer 1: PostgreSQL Append-Only テーブル

  • audit_logs テーブルに UPDATE / DELETE を拒否するトリガーを設定
  • アプリケーション用 DB ロールには INSERT 権限のみを付与(UPDATE, DELETE, TRUNCATE は付与しない)
sql
-- UPDATE/DELETE 拒否トリガー
CREATE OR REPLACE FUNCTION prevent_audit_log_modification()
RETURNS TRIGGER AS $$
BEGIN
    RAISE EXCEPTION 'audit_logs table does not allow UPDATE or DELETE';
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER audit_log_immutable
    BEFORE UPDATE OR DELETE ON audit_logs
    FOR EACH ROW EXECUTE FUNCTION prevent_audit_log_modification();

Layer 2: ハッシュチェーン

  • 各行の checksum は、前行の checksum + 当該行の全データ(checksum を除く)を連結した SHA-256 ハッシュ
  • テナントごとに独立したハッシュチェーンを構成
  • 日次検証バッチがチェーンの整合性を検証し、不整合検出時は Sev2 アラートを発報
checksum[n] = SHA-256(checksum[n-1] || tenant_id || actor_id || action || ... || created_at)

Layer 3: Cloud Storage Object Lock

  • 日次エクスポートバッチが監査ログを Cloud Storage にエクスポート
  • Retention Policy(7年)を設定し、物理的に削除不可とする
  • エクスポートファイルのハッシュを別バケットに保存し、改ざん検知に使用

パーティショニング戦略

月次レンジパーティション(pg_partman で自動管理):

ライフサイクル期間ストレージアクセスパターン
Hot0〜6ヶ月PostgreSQL(プライマリ)リアルタイムクエリ、ダッシュボード表示
Cool6ヶ月〜2年PostgreSQL(別テーブルスペース)管理者による検索、CSV エクスポート
Coldline2年〜7年Cloud Storage (Coldline)監査人による期間指定検索
削除7年超pg_partman による自動ドロップ + Cloud Storage ライフサイクルルールで削除

検索 SLO

利用者ユースケース対象期間SLO
企業管理者操作履歴 CSV エクスポート直近1年≤ 10秒
sys_adminリアルタイム操作監視直近24時間≤ 3秒
監査人全期間のマイナンバーアクセス履歴全期間(最大7年)≤ 1分

インデックス設計

インデックスカラム用途
ix_audit_logs_tenant_created(tenant_id, created_at)テナント別の時系列検索
ix_audit_logs_actor_created(actor_id, created_at)ユーザー別の操作履歴
ix_audit_logs_resource(resource_type, resource_id, created_at)リソース別の変更履歴
ix_audit_logs_mynumber_access(action) WHERE action = 'decrypt_mynumber'マイナンバーアクセス監査(部分インデックス)

→ 満たす要件: CR-003 監査・統制CR-010 監査ログ保持DM-901 AuditLog