Node.js XPath 인젝션

Node.js XPath 인젝션

설명

XPath 인젝션은 사용자 입력이 XPath 표현식에 직접 포함될 때 발생합니다. 공격자는 따옴표, 논리 연산자, 와일드카드 등을 주입해 의도하지 않은 노드를 조회하거나 인증 검사를 우회할 수 있습니다. Node.js의 xpath 라이브러리에서 동적으로 조립한 표현식을 select, select1, evaluate 등에 전달하는 패턴이 여기에 해당합니다.

잠재적 영향

  • XML 기반 인증이나 조회 로직을 우회할 수 있습니다.
  • 민감한 XML 노드나 추가 레코드가 노출될 수 있습니다.
  • XPath 식을 재사용하는 여러 엔드포인트에서 동일한 취약점이 반복될 수 있습니다.

해결 방법

  • 사용자 입력을 XPath 문자열에 직접 이어붙이지 마세요.
  • 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 문서이며 파싱과 데이터 접근 권한 확인은 생략했습니다. 이름 조회만으로 사용자를 인증하지 마세요.

참조