このページでは、 MongoDBクライアントライブラリを使用する場合にアプリケーションを開発するためのベストプラクティスについて説明します。以下の推奨事項に従って、インジェクション攻撃やその他のセキュリティの問題のリスクを減らし、アプリケーションが信頼できない入力を処理する際に発生する可能性があります。
SRV 接続文字列の使用
配置でサポートされている場合は、標準の mongodb://形式ではなく mongodb+srv://接続文字列形式を使用します。 +srv形式では、接続に対してトランスポート層セキュリティ(TLS)が自動的に有効になり、アプリケーションとMongoDBデプロイ間のトラフィックはデフォルトで暗号化されます。標準形式では、明示的に設定しない限り TLS は有効になりません。
+srv形式では、 DNS SRVレコードからシードホストの完全なリストも解決されます。基礎となるホストが変更された場合、接続文字列を更新する必要はありません。
警告
ドライバーは、元のシード ホスト名と同じ親ドメインを共有する SRV lookup の結果を信頼します。例、foo.example.com の検索では node1.foo.example.com が返される場合があります。また、foo.example.com の下になくても example.com 親ドメインを共有する node1.example.com が返される場合もあります。
悪意のある DNSサーバーまたは侵害された DNS サーバーは、接続設定中にアプリケーションを攻撃者が制御するホストにリダイレクトしようとすることがあります。親ドメインの制約 は、このリスクを制限します。シード ホスト名の親ドメインが、クラスター内のホスト、または同じ信頼できるエンティティによって制御されるクラスターにのみ解決されることを確認します。
詳細については、 MongoDB Serverマニュアルの 「SRV 接続形式」 と 「接続文字列」 を参照してください。
JSON をBSONに変換する前に信頼できない入力を検証する
多くのクライアントライブラリは、 拡張JSONを通じてJSON string をBSONドキュメントに変換する便利なメソッドを提供しています(例: )。アプリケーションが結果のドキュメントを検証せずにクエリ、アップデート、またはコマンドに渡すと、攻撃者はその操作の意味を変更することができます 。
JSONリクエスト本文を受け入れ、string 値を含む nameフィールドを期待するAPIエンドポイントを考えてみましょう。エンドポイントがリクエスト本体をBSONに変換し、その結果を検証なしでクエリフィルターで使用するとします。次の例に示すように、攻撃者は期待される string の代わりにオブジェクトを送信できます。
{"name": {"$ne": null}}
MongoDB は$neフィールドをリテラル値としてではなくクエリ演算子として評価します。このフィルターは、名前で単一のドキュメントを照合する代わりに、null 以外の nameフィールドを持つすべてのドキュメントを照合し、意図した以上のデータを表示します。
BSONに変換する前に信頼できない入力をJSON string に連結すると、同じリスクが発生します。次のC++ の例では、 string 連結を使用してユーザーが指定した値をJSON string に挿入してクエリフィルターを構築します。
std::string json_query = "{ \"name\": \"" + user_supplied_name + "\" }"; bsoncxx::document::value filter = bsoncxx::from_json(json_query); mongocxx::cursor cursor = collection.find(filter.view());
user_supplied_name に二重引用符またはJSON演算子が含まれている場合、結果の string は対象のフィールド値をエスケープし、任意のクエリ構文を挿入することができます。
このリスクは、 JSON string がユーザー、 APIリクエスト、またはアプリケーションが制御していない別のソースからのものである場合に適用されます。このリスクを軽減するには、 BSONに変換する前に信頼できない入力をタイプチェックして検証します。ドライバーの多くは、クエリの構築に使用できる 型指定されたドキュメントAPIまたは クエリ ビルダを提供しています。変換用のJSON入力を受け入れる前に、アプリケーション内でJSON schema または同様の検証レイヤーを適用することもできます。
次の例では、前の連結の例と同じフィルターを作成していますが、代わりに 型指定されたドキュメントビルダ を使用しています。
bsoncxx::builder::basic::document filter_builder; filter_builder.append( bsoncxx::builder::basic::kvp("name", user_supplied_name)); mongocxx::cursor cursor = collection.find(filter_builder.view());
ビルダは user_supplied_name を解析する string の一部としてではなく、 値として扱うため、値によってクエリの構造を変更することはできません。
string ではなくBSONドキュメントとしてクエリをビルドすると、攻撃者には操作されるクエリ文字列がないため、従来のSQLインジェクションを回避できます。詳細については、 MongoDB Serverマニュアルの「 FAQ: MongoDB の基礎 」を参照してください。拡張JSON のタイプと変換の詳細については、 MongoDB Serverマニュアルの「 MongoDB拡張JSON 」を参照してください。
サーバー側でのJavaScript実行を制限する
MongoDB$where は、 、$function 、$accumulator 、mapReduce など、 JavaScriptを実行する演算子とコマンドをサポートしています。アプリケーションがユーザー入力からこれらの式のいずれかを構築すると、サーバーはその入力をコードとして実行します。この動作は、アプリケーションコード内のeval 関数に信頼できない入力を渡すのと同じクラスのリスクを作成します。
このリスクを軽減するには、次の推奨事項に従ってください。
string の連結を避ける:
$where$function$accumulator信頼できない入力をJavaScript string に連結または挿入して、 式、 ボディ、または 関数を構築 しないでください 。 MongoDB はJavaScriptを実行せずに標準クエリ演算子を評価するため、代わりに標準クエリ演算子を使用します。サーバー側スクリプトを無効にする:アプリケーションで
$where、 、 、または$function$accumulatormapReducesecurity.javascriptEnabledfalsemongodmongos--noscriptingを使用していない場合は、サーバー側スクリプトを無効にします。 構成オプションを に設定するか、 または プロセスを開始して オプションを渡します。
サーバー側でのJavaScript の実行を保護する方法の詳細については、「 安全な構成オプションを使用してMongoDBを実行する 」を参照してください。
$where演算子の詳細については、 MongoDB Serverマニュアルの $where を参照してください。
詳細情報
自己管理型配置の保護に関するベストプラクティスのリストについては、 MongoDB Serverマニュアルの「 セキュリティ チェックリスト 」を参照してください。