説明
利用者の入力をXPath式に直接含めると、XPathインジェクションが発生するおそれがあります。引用符、論理演算子、ワイルドカードを挿入され、意図しないノードの取得や認証の回避につながる可能性があります。Node.jsのxpathライブラリで、動的に組み立てた式をselect、select1、evaluateなどへ渡す場合も同様です。
想定される影響
- XMLを使った認証や検索の処理を回避されるおそれがあります。
- 機密のXMLノードや追加のレコードが漏えいする可能性があります。
- 同じ式を複数のエンドポイントで使うと、同じ脆弱性が繰り返されるおそれがあります。
対処方法
- 利用者の入力をXPath式へ直接連結しないでください。
- 式を固定して値の比較をアプリケーションで行うか、ライブラリの変数バインディングを使ってください。
- 利用者に任意のXPathを書かせず、必要な検索の種類を許可リストで制限してください。
- 取得するノードと返すフィールドを最小限にし、リクエスト元のデータアクセス権限を別途確認してください。
例
変更前
javascript
const express = require("express");
const xpath = require("xpath");
const app = express();
app.get("/bad", (req, res) => {
const expr = "//users/user[@name='" + req.query.user + "']";
const result = xpath.select(expr, doc);
res.json(result.map((node) => ({ name: node.getAttribute("name") })));
});
変更後
javascript
const express = require("express");
const xpath = require("xpath");
const app = express();
app.get("/good", (req, res) => {
const user = req.query.user;
if (typeof user !== "string" || user.length > 100) {
return res.status(400).json({ error: "invalid user" });
}
const result = xpath.select("//users/user", doc)
.filter((node) => node.getAttribute("name") === user);
res.json(result.map((node) => ({ name: node.getAttribute("name") })));
});
変更前は入力によりXPathの構造を変えられます。変更後は固定の式でノードを選び、名前を値として比較するため、検索条件を維持しながらインジェクションを防ぎます。docは準備済みのXML文書で、解析とデータへのアクセス権限確認は省略しています。名前の検索だけで利用者を認証しないでください。