【入門編】NoSQLインジェクションのメカニズム(MongoDBを例に) – アプリケーションセキュリティ & 安全な開発防御ガイド

「SQLだけじゃない!」NoSQLインジェクションの脅威を、家の鍵に例えて徹底解説

こんにちは。セキュリティの現場を渡り歩いてきた者として、今日は皆さんに「NoSQLインジェクション」という、少し耳慣れないけれど非常に恐ろしい攻撃についてお話しします。

「SQLインジェクション」は聞いたことがある方も多いはず。でも、最近流行りのMongoDBのような「NoSQL」を使っているから安心……と思っていませんか? 実は、その安心こそが泥棒に「鍵、開けっ放しですよ」と教えているようなものなんです。

今日は、専門用語を極力使わず、家の防犯に例えて紐解いていきましょう!

—

1. NoSQLインジェクションって、何が起きているの?

想像してください。あなたは自分の家の玄関に「名前と合言葉(パスワード)」を書いてインターホンを押すシステムを導入しました。

  • 正しい使い方:
  • 名前:山田太郎
  • 合言葉:1234
  • (システムは「山田太郎で合言葉が1234の人、いるかな?」と確認します)

しかし、ここに「悪意のある来訪者」がやってきます。彼らは合言葉を知りません。そこで、こんなメモを置いていきます。

  • 攻撃者の仕掛け:
  • 名前:山田太郎
  • 合言葉:{“$ne”: “間違ったパスワード”}

この「$ne」というのは、プログラミングの世界で「〜と等しくない(Not Equal)」という意味の特殊な命令です。「合言葉が『間違ったパスワード』ではない人」という条件に変えてしまうわけです。システムは「あ、山田さんですね。合言葉は『間違ったパスワード』ではない(=正解!)ですね。どうぞ!」とドアを開けてしまいます。

これが、NoSQLインジェクションの正体です。「値」を入力するところに「命令(演算子)」を忍び込ませて、データベースを騙す手口ですね。

—

2. なぜ「JSON」が狙われるのか?

MongoDBのようなNoSQLは、データを「JSON」という形式でやり取りします。SQLの場合は、文字列の中に命令を混ぜ込むのが一般的でしたが、NoSQLは「データの中に命令を混ぜ込む」のが特徴です。

プログラム側が「送られてきた入力値は全部『文字』だよね」と信じ切っていると、攻撃者が送った {"$ne": null} という構造をそのままクエリ(データベースへの質問状)として解釈してしまい、無条件でログインを許可してしまうのです。

—

3. 「鍵のかけ方」を変える:明日からできる対策

では、どうやって防げばいいのでしょうか? 「型チェック」と「クエリの構築」という2つの盾を使いましょう。

対策①:入力された「型」を厳しくチェックする

一番の基本は、「文字列が来るはずの場所に、オブジェクト(命令)を入れさせない」ことです。

// 悪い例:入力値をそのままクエリに使ってしまう
const username = req.body.username;
const password = req.body.password;

// これだと、passwordにオブジェクトを入れられたらアウトです!
db.users.find({ username: username, password: password });

// 良い例:入力値が「文字列」であることを強制する
const username = String(req.body.username); // 強制的に文字列に変換
const password = String(req.body.password); // これならオブジェクトは文字列化され、命令として機能しない

db.users.find({ username: username, password: password });

対策②:バリデーションライブラリを導入する

「文字列に変換する」だけでは不安な場合、Joi や express-validator といった「入力値チェック専用の道具」を使いましょう。

// Joiを使った例
const schema = {
username: Joi.string().alphanum().required(), // 文字列で、英数字のみ許可
password: Joi.string().min(8).required() // 8文字以上の文字列のみ許可
};

// これ以外の形式(JSONオブジェクト等)が来たら即座に拒否!

—

4. 現場のプロからのアドバイス

新人の皆さんに一番伝えたいのは、「ユーザーからの入力を決して信じないでほしい」ということです。

ウェブサイトの入力フォームは、あなたの家の玄関です。そこには「名前を書く紙」しか置いてはいけません。でも、もし攻撃者が「これは家のドアをこじ開けるためのバールです」と書いて置いていったら、それをそのまま受け取ってはいけませんよね。

1. 型を疑う: それは本当に期待した「文字」ですか?
2. ライブラリに頼る: 自作のバリデーションは穴だらけです。信頼できるライブラリを使いましょう。
3. 最小権限の原則: アプリケーションがデータベースに接続する際、必要以上の権限を与えていませんか? 万が一突破されても、被害を最小限に抑えるのが「プロの守り」です。

セキュリティは一度やって終わりではありません。ですが、こうして少しずつ「相手の視点」を想像することで、あなたの書くコードは驚くほど堅牢になります。

一歩ずつ、一緒に学んでいきましょう! 次回は、さらに踏み込んだ「セッション管理の罠」についてお話しする予定です。もし疑問点があれば、いつでもコメント欄で教えてくださいね。応援しています!

コメント

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