web-dev-qa-db-ja.com

pythonコードでのMongoDB Nosqlインジェクション

MongoDBにアクセスするためのコードスニペットを次に示します。

client = MongoClient()
db = client.test_database
collection = db.test

# Get data from fields
condition = form.getvalue('name')
if condition:
    where = {"$where": "this.name == '"+condition+"'" }
else:
    where = ""

条件変数が適切にサニタイズされていないため、このコードはNoSQLインジェクションに対して脆弱であると言われました。しかし、Pythonでインジェクションがどのように機能するのか理解できませんでした。どんな入力が問題を引き起こす可能性があるか、または関連するインジェクション攻撃へのいくつかの参照のような例を誰かに教えてもらえますか?ちなみに私も自分でいくつか調べましたが、Javascriptに基づくインジェクションしか見つからず、このケースでは機能しませんでした。ありがとう。

11
Yang Yu

MongoDBの$where演算子は、避けた方がよい機能です。そのパフォーマンスはひどいものであり、インデックスの恩恵を受けていないだけではありません。ほぼすべての一般的なユースケースは、一般的な検索クエリまたは集計、特にこれほど簡単なものではるかに効率的に解決できます。しかし、これはスタックオーバーフローではなくセキュリティスタック交換なので、セキュリティの影響に焦点を当てましょう。

$whereステートメントは、JavaScriptコードスニペットをデータベースに渡し、データベースはコレクション内のドキュメントごとに1回実行されます。ありがたいことに、このスクリプトはdbオブジェクトやその他の危険なシェル関数にアクセスできず、ドキュメントのコピーに対して機能するため、攻撃者は少なくとも多くのSQLインジェクションのようにデータベースの内容を変更できません。しかし、たとえば、攻撃者が意図した以外の結果を返そうとする攻撃に対して脆弱です。

例を作ってみましょう。ブログがあるとしましょう。私たちのブログには一般公開できる記事がたくさんありますが、私たちの内部で使用するために公開されるべきではない非公開記事もいくつかあります。したがって、ドキュメントにはフィールドhiddenがあり、訪問者が記事を表示するかどうかに応じて、trueまたはfalseになります。 Webサイト訪問者に表示するために特定のカテゴリのすべての記事のリストを取得するためのMongoDBクエリは、次のようになります。

db.articles.find({"$where": "this.hidden == false && this.category == '"+category+"'" });

それは誰も私たちの隠された記事を見ないことを確実にするはずです。それともそうですか?ユーザーがcategory変数を制御するときに、次の文字列に設定できます。

'; return '' == '

データベースに送信される結果のJavaScriptスニペットは次のとおりです。

this.hidden == false && this.category == ''; return '' == ''

;で区切られた複数のコマンドを含むJavaScriptスニペットがある場合、それらは関数として実行され、呼び出し元に返される値を決定するためにreturnステートメントが必要です。この関数は常にtrueを返します。つまり、ユーザーは、非表示になっているものも含めて、コレクション内のすべての記事を見ることができます。

15
Philipp

どのような入力が問題を引き起こす可能性があるかなどの例を誰かに教えてもらえますか

あなたの具体的なコードではこれはうまくいくはずです:

'; while(1);var foo='bar

';は、文字列とステートメントをエスケープするために使用され、実際の攻撃while(1);(DOS攻撃)に従います。次に、まだ立っている'var foo='barを介して有効な構文に変換されます。

MongoDBのバージョン2.4までは、dbオブジェクトは実際にはグローバルだったので、データベース内のデータを変更したり、 ブラインドインジェクションを使用してデータを取得したり したりすることもできました。

それはもはや不可能であるため、攻撃者ができることのほとんどはDOSとフィリップによって記述されたフィルター回避です(これは例では問題ではありませんが、一般的に問題になる可能性があります)。

それはまだかなり悪いので、'"$をエスケープして、それに対して防御する必要があります。

8
tim