セキュリティナレッジにマルチテナントデータ分離セクションを追加
This commit is contained in:
parent
425f929134
commit
6153fd880a
@ -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 |
|
||||
|
||||
@ -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 チェックリスト
|
||||
|
||||
| カテゴリ | 確認事項 |
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user