MongoDBのセキュリティは、認証証明書を構成したり、データを暗号化したりするだけでは完全には保証されません。一部の攻撃者は、データベースのクエリプロセスの一部として使用されるHTTPリクエストで受信したパラメータを操作することで、「さらに一歩前進」します。
SQLデータベースはこのタイプの攻撃に対して最も脆弱ですが、MongoDBなどのNoSQLDBMでは外部インジェクションも可能です。ほとんどの場合、外部インジェクションは、クエリを作成する際の文字列の安全でない連結の結果として発生します。
外部インジェクション攻撃とは何ですか?
コードインジェクションは基本的に、検証されていないデータ(軽減されていないベクトル)を脆弱なプログラムに統合し、実行するとデータベースへの壊滅的なアクセスにつながります。その安全を脅かす。
サニタイズされていない変数がMongoDBクエリに渡されると、ドキュメントクエリの方向構造が壊れ、javascriptコード自体として実行されることがあります。これは、Nodejsサーバーのbody-parserモジュールから直接小道具を渡す場合によくあります。そのため、攻撃者は文字列や数字が予想される場所にJsオブジェクトを簡単に挿入できるため、望ましくない結果が得られたり、データが操作されたりする可能性があります。
{username:'John Doc', email:'[email protected]', age:20},
{username:'Rafael Silver', email:'[email protected]', age:30},
{username:'Kevin Smith', email:'[email protected]', age:22},
{username:'Pauline Wagu', email:'[email protected]', age:23}
プログラムでは、年齢が20歳のすべての学生を取得する必要があるとしましょう。このようなコードを作成すると、...
app.get(‘/:age’, function(req, res){
db.collections(“students”).find({age: req.params.age});
})
httpリクエストでJSONオブジェクトを
として送信します{age: 20}
これにより、年齢が20に等しいすべての学生が期待される結果として返されます。この場合は、{username:'John Doc'、email:'[email protected]'、age:20}のみが返されます。 。
ここで、攻撃者が数字の代わりにオブジェクトを送信したとします。つまり、{‘$ gt:0’};
db.collections( "students")。find({age:{‘$ gt:0’});これは、実行時にそのコレクション内のすべての生徒を返す有効なクエリです。攻撃者は、悪意に応じてデータを操作する機会があります。ほとんどの場合、攻撃者は、適切な手順なしでドキュメントにアクセスできるようにするMongoDBコマンドを含むカスタムオブジェクトを挿入します。
一部のMongoDBコマンドは、データベースエンジン内でJavascriptコードを実行します。これは、データに潜在的なリスクをもたらします。これらのコマンドには、「$ where」、「$ group」、「mapReduce」などがあります。 MongoDB 2.4より前のバージョンの場合、Jsコードはクエリ内からdbオブジェクトにアクセスできます。
MongoDB Naitive Protections
MongoDBは、クエリとドキュメントの両方にBSONデータ(バイナリJSON)を利用しますが、場合によっては、シリアル化されていないJSONおよびJs式(上記のような)を受け入れることができます。サーバーに渡されるデータのほとんどは文字列の形式であり、MongoDBクエリに直接フィードできます。 MongoDBはデータを解析しないため、直接パラメーターが統合されることで発生する可能性のある潜在的なリスクを回避できます。
APIにフォーマットされたテキストでのデータのエンコードが含まれ、そのテキストを解析する必要がある場合、その文字列がどのように解析されるかについて、サーバーの呼び出し元とデータベースの呼び出し先の間で不一致が生じる可能性があります。 。データが誤ってメタデータとして誤って解釈された場合、シナリオはデータにセキュリティ上の脅威をもたらす可能性があります。
MongoDB外部インジェクションの例とその処理方法
以下の学生コレクションのデータを考えてみましょう。
{username:'John Doc', password: ‘16djfhg’, email:'[email protected]', age:20},
{username:'Rafael Silver',password: ‘djh’, email:'[email protected]', age:30},
{username:'Kevin Smith', password: ‘16dj’, email:'[email protected]', age:22},
{username:'Pauline Wagu', password: ‘g6yj’, email:'[email protected]', age:23}
$ ne(等しくない)演算子を使用したインジェクション
リクエストから提供されたユーザー名とパスワードを使用してドキュメントを返したい場合、コードは次のようになります。
app.post('/students, function (req, res) {
var query = {
username: req.body.username,
password: req.body.password
}
db.collection(students).findOne(query, function (err, student) {
res(student);
});
});
POST https://localhost/students HTTP/1.1
Content-Type: application/json
{
"username": {"$ne": null},
"password": {"$ne": null}
}
この場合、最初の学生のユーザー名とパスワードはnullと評価されていないため、クエリは間違いなく最初の学生を返します。これは期待される結果とは異なります。
これを解決するには、次を使用できます:
mongo-sanitizeモジュール。「$」で始まるキーがMongoDBクエリエンジンに渡されるのを停止します。
最初にモジュールをインストールします
npm install mongo-sanitize
var sanitize = require(‘mongo-sanitize’);
var query = {
username: req.body.username,
password: req.body.password
}
mongooseを使用してスキーマフィールドを検証し、文字列を予期してオブジェクトを受け取った場合にクエリがエラーをスローするようにします。上記の場合、null値は文字列「」に変換されますが、文字通り影響はありません。
$where演算子を使用したインジェクション
var query = {
$where: “this.age > ”+req.body.age
}
db.collection(students).findOne(query, function (err, student) {
res(student);
});
この場合、「0」がある場合、サニタイズモジュールを使用しても役に立ちません。結果は、年齢が特定の値よりも大きい生徒ではなく、すべての生徒を返すためです。受け取ることができる他の可能な文字列は「\」です。 return \‘\’ ==\’’またはthis.email ===‘’; return‘’ ==‘’。このクエリは、句に一致する生徒だけでなく、すべての生徒を返します。
$where句は大幅に避ける必要があります。概説されたセットバックに加えて、インデックスを使用するように最適化されていないため、パフォーマンスも低下します。
$ where句で関数を渡す可能性も高く、MongoDBスコープで変数にアクセスできないため、アプリケーションがクラッシュする可能性があります。つまり
var query = {
$where: function() {
return this.age > setValue //setValue is not defined
}
}
代わりに、$ eq、$ lt、$ lte、$ gt、$gte演算子を使用することもできます。
- ユーザーデータを検証します。 $ where式を使用してデータにアクセスする方法を振り返ると、ユーザーがサーバーに送信する内容を常に検証することをお勧めします。
- JSONバリデーターの概念を使用して、マングースモジュールと一緒にスキーマを検証します。
- Jsコードがデータベースコードに完全にアクセスできないようにクエリを設計します。
MongoDBでは外部インジェクションも可能です。多くの場合、MongoDBクエリに入る未検証のユーザーデータに関連付けられています。サーバーが受信する可能性のあるデータをテストして、NoSQLインジェクションを検出および防止することが常に重要です。無視すると、ユーザーデータの安全性が脅かされる可能性があります。最も重要な手順は、関連するすべてのレイヤーでデータを検証することです。