OWASPテスティングガイドからNoSQLインジェクションの章を訳してみた

原文はこちら
Testing for NoSQL injection
https://www.owasp.org/index.php/Testing_for_NoSQL_injection

以下が訳です。

# NoSQLインジェクションの検証

## 概要
NoSQLデータベースが備える整合性制約は、従来のSQLデータベースよりも緩やかなものです。リレーショナル制約と一貫性チェックを少なくすることで、NoSQLデータベースはパフォーマンスとスケーリングのメリットにつながる場面が多くあります。従来のSQL構文を使用していないとしても、これらのデータベースはインジェクション攻撃に対して潜在的に脆弱です。これらのNoSQLインジェクション攻撃は、宣言型[[2]](http://ja.wikipedia.org/wiki/Declarative_programming) SQL言語ではなく、手続き型[[1]](https://ja.wikipedia.org/wiki/%E6%89%8B%E7%B6%9A%E3%81%8D%E5%9E%8B%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0)言語内で実行できるので、 潜在的影響は従来のSQLインジェクションよりも大きくなります。 

NoSQLデータベース呼び出しは、アプリケーションのプログラミング言語、カスタムAPI呼び出し、または一般的な規約（XML、JSON、LINQなど）に従って書かれます。これらの仕様を狙った悪意のある入力では、主要なアプリケーションのサニタイズチェックを引き起こさない場合があります。たとえば、特殊文字に<code>/ { } :</code>が含まれるJSON APIに対する攻撃では、 <code>< > & ;</code>などの一般的なHTML特殊文字のフィルタリングでは防ぐことはできません。

アプリケーション内で利用できるNoSQLデータベースは今や150以上の存在し[[3]](http://nosql-database.org/)、さまざまな言語や関係モデルでAPIが提供されています。機能と制限はそれぞれ異なります。それらの間に共通の言語がないため、サンプルのインジェクションコードはNoSQLデータベースを横断的には適用できません。このため、NoSQLインジェクション攻撃をテストする人は、特定のテストを作成するために、構文、データモデル、および基礎となるプログラミング言語に習熟している必要があります。

NoSQLインジェクション攻撃は、従来のSQLインジェクションとは別のアプリケーション領域で実行される場合があります。SQLインジェクションがデータベースエンジン内で実行される場合、使用されるNoSQL APIやデータモデルに応じて、アプリケーション層またはデータベース層内でNoSQLバリアントが実行されることがあります。通常、NoSQLインジェクション攻撃が実行されるのは、攻撃文字列がNoSQL APIコールに解析、評価、連結される場所です。

さらにタイミング攻撃は、NoSQLデータベース内での並行性検査の欠如に関連してくるものです。これらはインジェクションテストの対象としては扱いません。執筆時点では、MongoDBが最も広く使用されているNoSQLデータベースであるため、すべての例でMongoDB APIを使用していきます。

## テスト方法
**MongoDBのNoSQLインジェクション脆弱性のテスト：**
MongoDB APIは、BSON（Binary JSON）コールを要求し、セキュアなBSONクエリアセンブリツールも用意されています。しかし、MongoDBのドキュメントによると、シリアル化されていないJSONとJavaScriptの式は、いくつかの代替クエリパラメータで許可されています。 4任意のJavaScript入力を許可する最も一般的に使用されるAPI呼び出しは$ where演算子です。

MongoDB の$where演算子は通常、SQL内と同様に、シンプルなフィルタやチェックとして使用されます。

<code>db.myCollection.find( { $where: “this.credits`` ``==`` ``this.debits” } );</code>

必要に応じてJavaScriptも評価でき、より高度な条件が可能になります。

<code>db.myCollection.find( { $where: function() { return obj.credits - obj.debits < 0; } } );</code>

**例1**
$ where演算子に渡されるデータを攻撃者が操作できる場合、攻撃者は任意のJavaScriptを含めることでMongoDBクエリの一部として評価させることができます。ユーザー入力がサニタイズされずに直接MongoDBクエリに渡された場合に、脆弱性にさらけ出されてしまう例が次に示すコードです。

<code>db.myCollection.find( { active: true, $where: function() { return obj.credits - obj.debits < $userInput; } } );;</code>

他の種類のインジェクションをテストする場合と同様に、問題を実証するだけならこの脆弱性を完全にエクスプロイトする必要はありません。標的のAPI言語に関連する特殊文字を注入し、結果を観察することによって、テスターは、アプリケーションが入力を正しくサニタイズしているかどうかを判断できます。たとえばMongoDB内で、次のいずれかの特殊文字を含む文字列がサニタイズなしで渡された場合、データベースエラーが発生します。

<code>' " \ ; { }</code>

通常のSQLインジェクションでは、同様の脆弱性により、攻撃者は任意のSQLコマンドを実行し、意のままにデータを露出させたり操作したりできてしまいます。ただし、JavaScriptは完全な機能を備えた言語であるため、攻撃者はデータを操作できるだけでなく、任意のコードを実行することも可能です。たとえば、テスト時ならただエラーが発生だけですが、完全なエクスプロイトでは特殊な文字を使用して有効なJavaScriptを作成します。

この入力 <code>"(function(){var date = new Date(); do{curDate = new Date();}while(curDate-date<10000); return Math.max();})()"</code> を $userInput にインサートする上記の例では、このインジェクションは最初にサービスの拒否を引き起こすインライン関数を呼び出し、最終的に数値を返します。この特殊な攻撃文字列は、MongoDBインスタンス全体が100％CPU使用率で10秒間実行される事例です。

例2
たとえクエリ内で使用される入力が完全にサニタイズまたはパラメータ化されていても、NoSQLインジェクションをトリガーする代替パスがあります。多くのNoSQLインスタンスには、アプリケーションプログラミング言語とは独立の、独自の予約変数名があります。


たとえばMongoDB内では、 <code>$where</code>構文自体が予約済みのクエリ演算子です。表記のとおり正確にクエリに渡す必要があります。なにか変更したらデータベースエラーを発生させます。しかし、 <code>$where</code>は有効なPHP変数名でもあるので、 <code>$where</code>という名前のPHP変数を作成することで、攻撃者がクエリにコードを挿入できてしまう可能性があります。PHP MongoDBのドキュメントでは、開発者に明示的に警告しています：

<pre>すべての特別なクエリ演算子（$で始まる）に対してシングルクオートを使用していることを確認し、PHPが "$ exists"を$exists変数で置き換えようとしないようにしてください。</pre>

クエリがユーザの入力に依存しない場合でも、次の例のように、攻撃者が演算子を悪意のあるデータで置き換えることによってMongoDBをエクスプロイトできる可能性があります。

<code>db.myCollection.find( { $where: function() { return obj.credits - obj.debits < 0; } } );</code>


PHP変数にデータを割り当てる方法の1つは、HTTPパラメータ汚染です( Testing_for_HTTP_Parameter_pollution_(OTG-INPVAL-004))参照。パラメータ汚染を使って<code>$where</code>という名前の変数を作成すると、クエリの有効期限切れを示すMongoDBエラーが発生する可能性があります。文字列 "$ where"自身でない<code>$where</code>のいかなる値でも、脆弱性を証明するのに十分なはずです。攻撃者は、以下を挿入することで完全なエクスプロイトを開発します： <code>"$where: function() { //arbitrary JavaScript here }"</code>

## 参考文献

**インジェクションペイロード**
Injection payload wordlist with examples of NoSQL Injection for MongoDB - https://github.com/cr0hn/nosqlinjection_wordlists

**ホワイトペーパー**
Bryan Sullivan from Adobe: "Server-Side JavaScript Injection" - https://media.blackhat.com/bh-us-11/Sullivan/BH_US_11_Sullivan_Server_Side_WP.pdf

Bryan Sullivan from Adobe: "NoSQL, But Even Less Security" - http://blogs.adobe.com/asset/files/2011/04/NoSQL-But-Even-Less-Security.pdf

Erlend from Bekk Consulting: "[Security] NOSQL-injection" - http://erlend.oftedal.no/blog/?blogid=110

Felipe Aragon from Syhunt: "NoSQL/SSJS Injection" - http://www.syhunt.com/?n=Articles.NoSQLInjection

MongoDB Documentation: "How does MongoDB address SQL or Query injection?" - http://docs.mongodb.org/manual/faq/developers/#how-does-mongodb-address-sql-or-query-injection

PHP Documentation: "MongoCollection::find" - http://php.net/manual/en/mongocollection.find.php

"Hacking NodeJS and MongoDB" - http://blog.websecurify.com/2014/08/hacking-nodejs-and-mongodb.html

"Attacking NodeJS and MongoDB" - http://blog.websecurify.com/2014/08/attacks-nodejs-and-mongodb-part-to.html

[![クリエイティブ・コモンズ・ライセンス](https://i.creativecommons.org/l/by-sa/4.0/88x31.png)](http://creativecommons.org/licenses/by-sa/4.0/deed.ja)