【テクニカル・上級編】NoSQLインジェクション:MongoDBにおける$where演算子とJavaScript実行リスク – アプリケーションセキュリティ & 安全な開発防御ガイド

NoSQLの悪夢:MongoDB $where が招くサーバーサイドJSインジェクションの深淵

「SQLインジェクションはもう古い」と高を括っているテックリードは少なくない。確かに、ORMの普及やプリペアドステートメントの一般化により、従来の文字列連結によるクエリ汚染は過去のものとなりつつある。しかし、NoSQL、特にMongoDBの運用現場において、我々は別の「地雷」を抱え込んでいることに気づいていない。

それが、$where 演算子だ。これは単なるクエリ演算子ではない。DBエンジン内部のJavaScript実行環境(SpiderMonkey)を直接叩くためのバックドアにもなり得る、極めて危険なパンドラの箱である。

1. $where が抱える根本的な設計上の欠陥

MongoDBにおける $where 演算子は、サーバー側で任意のJavaScript式を評価する機能だ。DB管理者は「柔軟なフィルタリング」として重宝するが、攻撃者から見れば「サーバー側でコードを実行できるゲートウェイ」に過ぎない。

なぜこれが致命的か。それは、アプリケーション層から渡されるパラメータが、構文解析を経ずにそのままJavaScriptの評価コンテキストに流し込まれるからだ。

// 脆弱な実装例:ユーザー入力をそのまま連結
// リクエスト例: ?username=admin’ || ‘1’==’1
const query = { $where: “this.username == ‘” + req.query.username + “‘” };
db.users.find(query);

このコードに対し、admin' || '1'=='1 という入力を与えれば、生成される式は this.username == 'admin' || '1'=='1' となる。結果、全ユーザーの認証をバイパスしてレコードが抽出される。さらに悪質な場合、'; while(true){} のようなコードを注入すれば、サーバーのCPUリソースを枯渇させるDoS攻撃が瞬時に成立する。これは通信プロトコル上の欠陥ではなく、「クエリ言語内で動的実行環境を許容した設計」そのものの帰結だ。

2. メモリとコンテキストの危うい均衡

この脆弱性の核心は、MongoDBのプロセス内で実行されるSpiderMonkeyエンジンが、クエリのスコープ外にあるグローバルなコンテキストにアクセスできてしまう点にある。

攻撃者は単なるデータ抽出に留まらず、プロトタイプの汚染や、さらにはDBサーバーのファイルシステムに触れるAPIを呼び出す試み(バージョンや設定によるが)すら行う可能性がある。インシデントハンドリングの現場で私が遭遇するのは、この $where を経由した「権限昇格」の痕跡だ。アプリケーション層でどれほど堅牢な認証を実装していようが、DBの心臓部でコードが走ってしまえば、その防御壁は紙のように薄い。

3. 防御の最前線:アーキテクチャによる「根絶」

この脅威に対して、パッチやブラックリスト運用で対抗するのは愚策だ。セキュリティアーキテクトとして推奨するのは、以下の二段構えの防衛策である。

A. $where の完全禁止と標準クエリへの置換

まず、開発規約として $where の使用を完全に禁止(Lintルールによる強制)せよ。代わりに、MongoDBの標準的なクエリ演算子($eq, $in, $regex 等)を使用する。これらはバイナリ形式(BSON)で受け渡されるため、構文解析のプロセスでコード注入が遮断される。

// 改善例:標準クエリ演算子による安全な実装
// BSONレベルで型が保証されるため、JSインジェクションは物理的に不可能
db.users.find({ username: req.query.username });

B. スキーマバリデーションによるガードレイル

MongoDBの collMod コマンドでスキーマバリデーションを定義し、アプリケーションの記述ミスが万が一発生しても、不正なクエリが実行されないようセーフティネットを張る。

// MongoDBシェルでのスキーマバリデーション設定
db.runCommand({
collMod: “users”,
validator: {
$jsonSchema: {
bsonType: “object”,
required: [“username”],
properties: {
username: { bsonType: “string” } // 型を厳格に制限
}
}
}
});

4. 次世代を見据えたセキュリティ設計の視点

現在、我々が対峙しているのは単なるSQL/NoSQLインジェクションだけではない。生成AIによるコード生成が標準化される中で、LLMが「利便性のために」 $where を使用したコードを平気で提案する時代になった。

防御側にとっての新たな脅威は、「AIが生成した脆弱なコードを、セキュリティ意識の低いジュニアエンジニアがそのままデプロイする」というプロセスそのものにある。

今後、我々が実装すべきは、CI/CDパイプラインにおける「動的解析を模した静的解析」だ。プロンプトインジェクションに対するガードレイルと同様に、DBへのクエリ実行前に、「ユーザー入力がクエリの一部に直結していないか」を静的解析ツールで検知し、ブロックする仕組みをアーキテクチャの根幹に組み込む必要がある。

最後に

セキュリティとは、技術の積み重ねであると同時に、哲学でもある。$where のような「便利だが危険な機能」を安易に許容する文化は、いずれ組織を破滅させる。

「もし君がコードを書くとき、そのクエリが攻撃者の手によって書き換えられたらどうなるか?」

この問いを自問し続けることが、我々エンジニアが持つべき唯一の武器であり、信頼を勝ち取るための絶対条件だ。技術の深淵を覗くときは、自らもまた覗かれているということを忘れてはならない。

コメント

タイトルとURLをコピーしました