diff --git a/builtins/en/knowledge/security.md b/builtins/en/knowledge/security.md index 6c9d844..de2b945 100644 --- a/builtins/en/knowledge/security.md +++ b/builtins/en/knowledge/security.md @@ -148,6 +148,46 @@ if (!safePath.startsWith(path.resolve(baseDir))) { - Resource exhaustion attack possibility → Warning - Infinite loop possibility → REJECT +## Multi-Tenant Data Isolation + +Prevent data access across tenant boundaries. Authorization (who can operate) and scoping (which tenant's data) are separate concerns. + +| Criteria | Verdict | +|----------|---------| +| Reads are tenant-scoped but writes are not | REJECT | +| Write operations use client-provided tenant ID | REJECT | +| Endpoint using tenant resolver has no authorization control | REJECT | +| Some paths in role-based branching don't account for tenant resolution | REJECT | + +### Read-Write Consistency + +Apply tenant scoping to both reads and writes. Scoping only one side creates a state where data cannot be viewed but can be modified. + +When adding a tenant filter to reads, always add tenant verification to corresponding writes. + +### Write-Side Tenant Verification + +For write operations, use the tenant ID resolved from the authenticated user, not from the request body. + +```kotlin +// NG - Trusting client-provided tenant ID +fun create(request: CreateRequest) { + service.create(request.tenantId, request.data) +} + +// OK - Resolve tenant from authentication +fun create(request: CreateRequest) { + val tenantId = tenantResolver.resolve() + service.create(tenantId, request.data) +} +``` + +### Authorization-Resolver Alignment + +When a tenant resolver assumes a specific role (e.g., staff), the endpoint must have corresponding authorization controls. Without authorization, unexpected roles can access the endpoint and cause the resolver to fail. + +For endpoints with role-based branching, verify that tenant resolution succeeds on all paths. + ## OWASP Top 10 Checklist | Category | Check Items | diff --git a/builtins/ja/knowledge/security.md b/builtins/ja/knowledge/security.md index 14ab513..1e5d91a 100644 --- a/builtins/ja/knowledge/security.md +++ b/builtins/ja/knowledge/security.md @@ -148,6 +148,46 @@ if (!safePath.startsWith(path.resolve(baseDir))) { - リソース枯渇攻撃の可能性 → 警告 - 無限ループの可能性 → REJECT +## マルチテナントデータ分離 + +テナント境界を超えたデータアクセスを防ぐ。認可(誰が操作できるか)とスコーピング(どのテナントのデータか)は別の関心事。 + +| 基準 | 判定 | +|------|------| +| 読み取りはテナントスコープだが書き込みはスコープなし | REJECT | +| 書き込み操作でクライアント提供のテナントIDを使用 | REJECT | +| テナントリゾルバーを使うエンドポイントに認可制御がない | REJECT | +| ロール分岐の一部パスでテナント解決が未考慮 | REJECT | + +### 読み書きの一貫性 + +テナントスコーピングは読み取りと書き込みの両方に適用する。片方だけでは、参照できないが変更できる状態が生まれる。 + +読み取りにテナントフィルタを追加したら、対応する書き込みも必ずテナント検証する。 + +### 書き込みのテナント検証 + +書き込み操作では、リクエストボディのテナントIDではなく認証済みユーザーから解決したテナントIDを使う。 + +```kotlin +// NG - クライアント提供のテナントIDを信頼 +fun create(request: CreateRequest) { + service.create(request.tenantId, request.data) +} + +// OK - 認証情報からテナントを解決 +fun create(request: CreateRequest) { + val tenantId = tenantResolver.resolve() + service.create(tenantId, request.data) +} +``` + +### 認可とリゾルバーの整合性 + +テナントリゾルバーが特定ロール(例: スタッフ)を前提とする場合、エンドポイントに対応する認可制御が必要。認可なしだと、前提外のロールがアクセスしてリゾルバーが失敗する。 + +ロール分岐があるエンドポイントでは、全パスでテナント解決が成功するか検証する。 + ## OWASP Top 10 チェックリスト | カテゴリ | 確認事項 |