メインコンテンツまでスキップ

マルチテナントセキュリティ

このドキュメントの目的

マルチテナントSaaSにおけるデータ分離以外のセキュリティを理解し、テナント間の安全性を確保する設計ができるようになることが目標です。

データパーティション化とテナント分離ではデータの分離方法(RLS等)を、テナント別設定管理テナントカスタマイズパターンではテナントごとの挙動制御を学びました。本記事では、認証分離、権限設計、監査、レート制限、インシデント対応などデータ分離以外のセキュリティ全般に焦点を当てます。

具体例について: 本記事ではIDサービスを題材にした例(OAuth トークン、セッション分離等)を使用していますが、マルチテナントセキュリティの原則はSaaS全般に共通です。


テナント間の認証分離

セッション分離

マルチテナント環境では、あるテナントのセッションが別のテナントで利用されてはなりません。

正しいセッション分離:

Tenant A: Session-A ──> Tenant Aのリソースにのみアクセス可能
Tenant B: Session-B ──> Tenant Bのリソースにのみアクセス可能

クロステナント攻撃(防止すべき):

攻撃者: Session-A ──> Tenant Bのリソースにアクセス(NG!)

セッション分離の実装方法:

方式説明セキュリティレベル
セッションにテナントIDを紐付けセッション作成時にtenant_idを記録し、リクエスト時に検証基本
Cookie Domain分離テナントごとに異なるドメイン(tenant-a.example.com
セッションストア分離テナントごとに異なるセッションストアを使用最高

トークンスコープの分離

OAuth 2.0トークンには、テナント情報を含めてクロステナントアクセスを防止します。

アクセストークンの構造:

{
"sub": "user-123",
"tenant_id": "tenant-a", ← テナントの明示
"scope": "read:users",
"iss": "https://tenant-a.example.com",
"aud": "https://api.example.com"
}

検証フロー:

リクエスト受信


┌──────────────────┐
│ 1. トークン検証 │ ← 署名、有効期限
├──────────────────┤
│ 2. テナントID検証 │ ← トークンのtenant_idとリクエスト先が一致
├──────────────────┤
│ 3. スコープ検証 │ ← 操作に必要なスコープがあるか
└──────────────────┘


アクセス許可 or 拒否

クロステナント攻撃の防止

主要な攻撃パターンと対策:

攻撃パターン説明対策
テナントID改ざんリクエストのテナントIDを書き換えトークン内のtenant_idと照合
セッション固定攻撃他テナントのセッションを利用セッションにtenant_idを紐付け
IDOR(Insecure Direct Object Reference)他テナントのリソースIDを推測リソースアクセス時にtenant_idを検証
JWT混同攻撃異なるテナントのJWTを流用issuer(iss)をテナント単位で検証
認可コード横取り他テナントの認可コードを利用認可コードにtenant_idを紐付け

テナント管理者の権限設計

ロールベースアクセス制御(RBAC)

テナント内の権限はロールで管理します。システム管理者とテナント管理者を明確に区別します。

権限の階層:

┌──────────────────────────────────────────┐
│ システム管理者(SaaS運営者) │
│ │
│ ・全テナントの管理 │
│ ・テナントの作成・削除 │
│ ・システム設定の変更 │
│ ・プラン・課金の管理 │
├──────────────────────────────────────────┤
│ テナント管理者(顧客の管理者) │
│ │
│ ・自テナント内のユーザー管理 │
│ ・自テナントの設定変更 │
│ ・自テナントの監査ログ閲覧 │
│ ・他テナントへのアクセスは一切不可 │
├──────────────────────────────────────────┤
│ テナントユーザー(顧客のエンドユーザー) │
│ │
│ ・自分のプロファイル管理 │
│ ・許可されたリソースへのアクセス │
│ ・管理機能へのアクセスは不可 │
└──────────────────────────────────────────┘

最小権限の原則

テナント管理者には必要最小限の権限のみを付与します。

権限マトリックス:

操作 │ システム管理者 │ テナント管理者 │ テナントユーザー
────────────────────────┼───────────────┼───────────────┼────────────────
テナント作成・削除 │ ○ │ × │ ×
テナント設定変更 │ ○ │ ○ │ ×
ユーザー作成・削除 │ ○ │ ○ │ ×
ユーザープロファイル閲覧 │ ○ │ ○ │ 自分のみ
監査ログ閲覧 │ 全テナント │ 自テナント │ ×
他テナントデータ閲覧 │ ○ │ × │ ×

権限エスカレーション防止

テナント管理者が自分の権限をシステム管理者レベルに昇格させることを防ぎます。

防止すべきパターン:

1. テナント管理者が自分にシステム管理者ロールを付与
→ 対策: ロール付与APIで上位ロールの付与を禁止

2. テナント管理者が他テナントの管理者ロールを取得
→ 対策: ロール操作は自テナント内に限定

3. テナント管理者がAPI直接呼び出しで権限チェックを回避
→ 対策: 全APIエンドポイントでサーバーサイド権限チェック

実装のポイント:

  • ロール付与は「自分と同じか下位のロール」のみ許可
  • テナント境界を越えるロール操作は一律拒否
  • 権限チェックはクライアントサイドではなくサーバーサイドで実施

監査とコンプライアンス

テナント別監査ログ

マルチテナント環境では、監査ログもテナント単位で分離する必要があります。

監査ログの構造:

┌────────────────────────────────────────────────────────┐
│ timestamp │ tenant_id │ actor │ action │ target │
├──────────────┼────────────┼──────────┼─────────┼────────┤
│ 2024-01-01 │ tenant-a │ admin-1 │ CREATE │ user-5 │
│ 2024-01-01 │ tenant-b │ admin-2 │ UPDATE │ config │
│ 2024-01-02 │ tenant-a │ user-3 │ LOGIN │ - │
└──────────────┴────────────┴──────────┴─────────┴────────┘

テナント管理者の閲覧:
Tenant A管理者 → tenant_id = "tenant-a" のログのみ閲覧可能
Tenant B管理者 → tenant_id = "tenant-b" のログのみ閲覧可能

記録すべきイベント

カテゴリイベント重要度
認証ログイン成功/失敗、MFA成功/失敗、パスワード変更
管理操作ユーザー作成/削除、ロール変更、設定変更
データアクセス個人情報の閲覧、データエクスポート
セキュリティアカウントロック、異常アクセス検知、トークン失効
テナント管理テナント設定変更、プラン変更

データレジデンシー

法規制により、テナントのデータを特定の地理的リージョンに保存する義務がある場合があります。

データレジデンシー要件:

┌─────────────────┐ ┌─────────────────┐
│ EU テナント │ │ 日本テナント │
│ │ │ │
│ データ保存先: │ │ データ保存先: │
│ EU リージョン │ │ 東京リージョン │
│ (GDPR準拠) │ │ (個人情報保護法) │
└─────────────────┘ └─────────────────┘
規制要件対象地域
GDPREU市民のデータはEU内、または十分性認定国で処理EU/EEA
個人情報保護法外国にある第三者への提供に本人同意が必要日本
CCPAカリフォルニア州住民の個人情報保護米国カリフォルニア

コンプライアンスフレームワーク

SaaSで一般的に求められるコンプライアンス要件:

フレームワーク対象監査ログ要件
SOC 2 Type IISaaS全般アクセスログ、変更ログを1年以上保持
ISO 27001情報セキュリティ全般インシデント記録、リスク評価の文書化
PCI DSS決済データ処理全アクセスを90日間オンライン保持
HIPAA医療データ(米国)監査ログを6年間保持

レート制限とクォータ

なぜテナント別のレート制限が必要か

マルチテナント環境では、1つのテナントがリソースを過剰に消費すると、他のテナントに影響します(Noisy Neighbor問題)。テナント別のレート制限により、公平なリソース配分を実現します。

レート制限なし:

Tenant A: 100 req/s ─┐
Tenant B: 10,000 req/s ├──> 共有リソース ──> Tenant Aが遅延
Tenant C: 50 req/s ─┘

レート制限あり:

Tenant A: 100 req/s ─┐
Tenant B: 1,000 req/s ├──> 共有リソース ──> 全テナント安定
(制限超過分は429) │
Tenant C: 50 req/s ─┘

Tier別レート制限の設計

Tierリクエスト制限ユーザー数上限同時接続数ストレージ
Free100 req/s100501 GB
Standard1,000 req/s1,00050010 GB
Enterprise10,000 req/s無制限5,000100 GB
Dedicatedカスタムカスタムカスタムカスタム

レート制限のアルゴリズム

アルゴリズム説明特徴
Fixed Window固定時間枠でカウント(例: 1分間に100回)シンプル、境界付近でバーストが起きうる
Sliding Window過去N秒間のリクエスト数でカウント境界問題なし、メモリ使用量が多い
Token Bucketトークンが一定速度で補充され、リクエスト時に消費バースト許容、平均レートを制御
Leaky Bucketリクエストをキューに入れ、一定速度で処理出力レートが一定、レイテンシー増加

レート制限超過時のレスポンス

HTTP/1.1 429 Too Many Requests
Retry-After: 30
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1704067200

{
"error": "rate_limit_exceeded",
"message": "Rate limit exceeded. Try again in 30 seconds.",
"retry_after": 30
}

レスポンスヘッダー:

ヘッダー説明
Retry-Afterリトライまでの待機秒数
X-RateLimit-Limit制限値
X-RateLimit-Remaining残りリクエスト数
X-RateLimit-Reset制限リセットのUNIXタイムスタンプ

インシデント対応

テナント単位のサスペンド

セキュリティインシデントが発生した場合、影響を受けたテナントを迅速にサスペンドして被害拡大を防止します。

インシデント発生時のフロー:

インシデント検知


┌──────────────────┐
│ 1. 影響範囲特定 │ ← どのテナントが影響を受けているか
└──────────┬───────┘

┌─────┼─────┐
▼ ▼ ▼
┌────────┐ ┌────────┐
│影響あり │ │影響なし │
│テナント │ │テナント │
│ │ │ │
│サスペンド│ │通常稼働 │
└────┬───┘ └────────┘


┌──────────────────┐
│ 2. 調査・対応 │ ← 原因究明、修正
└──────────┬───────┘


┌──────────────────┐
│ 3. 復旧 │ ← サスペンド解除
└──────────┬───────┘


┌──────────────────┐
│ 4. 事後対応 │ ← 報告、再発防止
└──────────────────┘

サスペンド時の挙動

テナントがサスペンドされた場合の各コンポーネントの挙動を明確に定義します。

コンポーネントサスペンド時の挙動
認証新規ログイン拒否、既存セッション無効化
API全リクエストに HTTP 403 を返却
管理APIテナント管理者のアクセスを無効化
バッチ処理テナント関連のジョブをスキップ
通知テナント管理者へサスペンド通知メール
データデータの読み取り・書き込みともに不可

影響範囲の限定

マルチテナント環境でのインシデント対応では、影響を受けていないテナントへの影響を最小化することが重要です。

影響範囲の限定:

インシデント: Tenant Aのクレデンシャル漏洩

対応:
Tenant A → サスペンド、全セッション無効化、パスワードリセット強制
Tenant B → 通常稼働(影響なし)
Tenant C → 通常稼働(影響なし)

誤った対応:
全テナント → サスペンド(過剰対応、ビジネスインパクト大)

インシデント対応のチェックリスト

検知・初動(0〜30分):
[ ] アラート確認、インシデントの分類(重大度)
[ ] 影響を受けたテナントの特定
[ ] 該当テナントのサスペンド(必要な場合)
[ ] インシデント対応チームへのエスカレーション

調査・封じ込め(30分〜数時間):
[ ] 根本原因の調査
[ ] 影響範囲の確定(データ漏洩、不正アクセス等)
[ ] 追加の封じ込め措置(IPブロック、トークン無効化等)

復旧(数時間〜数日):
[ ] 根本原因の修正
[ ] 影響を受けたテナントへの通知
[ ] テナントのサスペンド解除
[ ] クレデンシャルリセット(必要な場合)

事後対応(数日〜数週間):
[ ] インシデント報告書の作成
[ ] 影響を受けたテナントへの詳細報告
[ ] 再発防止策の策定・実施
[ ] コンプライアンス上の報告義務対応(GDPR: 72時間以内等)

セキュリティチェックリスト

マルチテナントSaaSのセキュリティ設計で確認すべき項目をまとめます。

認証・セッション

  • セッションにテナントIDが紐付けられている
  • トークンにテナント情報が含まれている
  • テナント間でセッション・トークンの流用ができない
  • 認可コードにテナントIDが紐付けられている

権限

  • テナント管理者は自テナント内の操作のみ可能
  • 権限エスカレーションが防止されている
  • 全APIエンドポイントでサーバーサイド権限チェックが実装されている
  • リソースアクセス時にテナントIDの検証が行われている

監査・コンプライアンス

  • テナント別の監査ログが記録されている
  • テナント管理者は自テナントのログのみ閲覧可能
  • データレジデンシー要件が満たされている
  • コンプライアンスフレームワークの要件を満たしている

リソース保護

  • テナント別のレート制限が設定されている
  • リソースクォータが設定されている
  • レート制限超過時に適切なレスポンスが返される

インシデント対応

  • テナント単位のサスペンドが可能
  • 影響範囲を限定する仕組みがある
  • インシデント対応手順が文書化されている

まとめ

学んだこと

  • セッションとトークンにテナントIDを紐付けて認証分離を実現する
  • システム管理者・テナント管理者・テナントユーザーの3階層で権限を設計する
  • 権限エスカレーション防止には、ロール付与の制約とサーバーサイド検証が必要
  • 監査ログはテナント単位で分離し、コンプライアンス要件に応じた保持期間を設定する
  • テナント別のレート制限・クォータでNoisy Neighbor問題に対処する
  • インシデント対応は影響テナントのみをサスペンドし、影響範囲を限定する

次のステップ

  1. データパーティション化とテナント分離 - データ分離の詳細
  2. セキュリティ学習コンテンツ - Webアプリケーションセキュリティ全般

最終更新: 2026-03-03 対象: SaaSアプリケーション開発者・セキュリティエンジニア