Zen Firewall による IDOR 保護
IDORは Insecure Direct Object Reference の略です。これは、データベースクエリのスコープが適切でないために、あるアカウントが別のアカウントのデータにアクセスできてしまうアクセス制御バグの一種です。
マルチテナントの SaaS アプリケーションでは、データは通常 tenant_id、account_id、organization_id などの列で分離されます。クエリがその列でのフィルタリングを忘れたり、誤った値を使ったりすると、アカウント間でデータが漏れる可能性があります。
Zen Firewall の IDOR Protection は、実行時に SQL クエリを解析し、テナントのスコーピングを自動的に強制します。クエリが安全でない場合、Zen は即座にエラーを投げます。
これにより、本番での障害の後ではなく、開発やテストの段階でマルチテナント分離のバグを見つけられます。
この脆弱性そのものについてより詳しく知りたい場合は、ブログ記事を参照してください: IDOR 脆弱性の解説
サポート対象データベース
現在サポートされているドライバ:
mysql および mysql2 経由の MySQL
pg 経由の PostgreSQL
SQLite(better-sqlite3 および node:sqlite パッケージ経由)
内部でこれらのドライバを使用する任意の ORM またはクエリビルダーがサポートされています。たとえば Drizzle、Knex、Sequelize、TypeORM などです。
Prisma のように独自のクエリエンジンを使用する ORM は、サポート対象のドライバアダプタを使うように設定されていない限りサポートされません。
制限事項
Zen が保護するもの
有効にすると、Zen は各関連クエリが次を満たすことを検証します:
SELECT、UPDATE、DELETE で正しいテナント列をフィルタリングしていること
正しいテナント ID 値を使用していること
すべての INSERT にテナント列が含まれていること
INSERT でテナント列に正しいテナント ID が設定されていること
Zen がブロックする問題の例:
テナントフィルターのない SELECT により、あるアカウントが別のアカウントのデータを読み取れてしまう
テナントのスコープ指定のない UPDATE または DELETE
テナント列を省略した INSERT
誤ったテナント ID を設定する INSERT
IDOR 保護は、block モードでも detect モードでも、違反があると常に Error を投げます。テナントフィルターの欠如は外部攻撃ではなく、開発者のバグです。
仕組み
Zen はサポート対象のデータベースドライバを計装し、実行時に SQL クエリを検査します。各リクエストでアクティブなテナント ID を設定すると、Zen はその後、関連するすべてのクエリが次を満たすことを確認します:
設定されたテナント列を参照している。
そのリクエストに対して設定されたものと同じテナント ID を使用している。
クエリがこれらの条件を満たさない場合、Zen はエラーを投げて実行を防ぎます。
セットアップ
起動時に IDOR 保護を有効にする
アプリケーションの起動時に IDOR 保護を有効にします
設定オプション:
tenantColumnNameテーブル内でテナントを識別する列です。たとえば tenant_id、account_id、organization_id などです。
excludedTables単一テナントにスコープされていないため、チェックすべきでないテーブルです。たとえば、すべてのテナントにまたがるユーザーを含む共有 users テーブルなどです。
リクエストごとにテナント ID を設定する
IDOR 保護が有効な場合、すべてのリクエストにテナント ID が必要です。
setTenantId は、リクエストのライフサイクルの早い段階で、通常は認証後のミドルウェア内で呼び出してください。
リクエストに対して setTenantId が呼び出されていない場合、SQL クエリが実行されると Zen は Error を投げます。
特定のクエリで IDOR チェックをバイパスする
一部のクエリは、たとえばテナント横断の分析や内部管理レポートなど、意図的にグローバルです。
特定のコードブロックで IDOR チェックをスキップするには、withoutIdorProtection を使います:
コールバック内で実行されたクエリのみが IDOR 検証の対象外になります。
これは慎重に使い、かつクロステナントアクセスが明示的に必要な箇所にのみ使用してください。
トラブルシューティング
テナントフィルターがない
このクエリは、設定されたテナント列でフィルタリングしていません。これは SELECT、UPDATE、DELETE に適用されます。
例:
tenant_id でフィルタリングする条件を追加してください。
テナント ID の値が間違っている
このクエリはテナント列でフィルタリングしていますが、その値がで設定されたテナント ID と一致しません setTenantId.
すべてのクエリが現在のリクエストコンテキストのテナント ID を使用するようにしてください。
INSERT にテナント列がない
すべての INSERT にはテナント列を含める必要があります。
INSERT のテナント ID が間違っている
INSERT にはテナント列が含まれていますが、その値がアクティブなテナント ID と一致しません。
`setTenantId` 呼び出しがない
データベースクエリが実行される前に、すべてのリクエストで setTenantId が呼び出されていることを確認してください。
常に許可されるステートメント
Zen がチェックするのは、行データを読み取るか変更するステートメントのみです:
SELECT
INSERT
UPDATE
DELETE
以下は認識され、IDOR エラーを一切発生させません:
CREATE TABLE、ALTER TABLE、DROP TABLE などの DDL ステートメント
SET、SHOW などのセッションコマンド
BEGIN、COMMIT、ROLLBACK などのトランザクションステートメント
最終更新
役に立ちましたか?