FlawOpen

flawopen.com/JavaScript의 SQL Injection/Knex.js

Knex.js는 SQL Injection에 안전한가요?

참고 가이드
간단한 답변

SQL을 인쇄된 양식이라고 생각해 보세요. binding은 입력을 값 칸에 넣지만 문자열 보간은 지시문에 붙입니다. Knex query builder와 knex.raw(sql, bindings)는 값을 분리합니다. 테이블명과 컬럼명은 SQL 구조이므로 신뢰할 수 있는 허용 목록을 사용해야 합니다.

??는 Knex raw 식별자 placeholder로 식별자를 인용하지만 선택 권한을 주지는 않습니다. 허용 목록으로 제한하세요.
안전 — bindings와 허용 목록
const query = knex.raw(
  `SELECT * FROM users WHERE id = ${userId}`
);
위험 — 입력으로 SQL 조립
// 입력을 SQL 소스에 연결합니다.
const allowedSortColumns = new Set(["created_at", "name"]);

const rows = await knex("users")
  .where("id", userId)
  .orderBy(
    allowedSortColumns.has(requestedSort)
      ? requestedSort
      : "created_at",
    requestedDirection === "asc" ? "asc" : "desc"
  );

// 값을 SQL 구문과 분리합니다.
knex.raw("SELECT * FROM users WHERE id = ?", [userId]);

Knex bindings가 값을 보호하는 방식

.where(), .insert(), .select() 같은 메서드는 값을 생성 SQL과 분리합니다. raw에는 값을 bindings로 전달하세요: knex.raw("... = ?", [value]). ?는 값, ??는 식별자입니다. 입력을 SQL 템플릿 문자열에 보간하지 마세요.

동적 식별자에는 허용 목록이 필요합니다

binding은 사용자가 고른 컬럼, 테이블, 정렬, 연산자 또는 SQL 조각을 허용하지 않습니다. ??는 식별자를 인용하지만 선택 권한을 판단하지 않습니다. .orderBy()에 전달하기 전에 고정 허용 목록에 매핑하고 SQL 키워드와 연산자는 코드에 고정하세요.

raw 쿼리 감사 방법

모든 knex.raw()를 찾아 SQL 문자열과 bindings를 함께 검토하세요. 값은 bindings로, 동적 식별자는 작은 허용 목록으로 제한해야 합니다. raw 쿼리가 자동으로 취약한 것은 아니며 SQL과 입력을 만드는 방식이 중요합니다.

rg -n 'knex\.raw\(' -g '*.js' -g '*.ts' -g '*.mjs' -g '*.cjs' .

자주 묻는 질문

knex.raw() 자체가 SQL Injection을 막아 주나요?

아니요. knex.raw("... = ?", [value])처럼 bindings로 신뢰할 수 없는 값을 전달하세요. 문자열 보간은 값을 SQL 소스에 포함시킵니다. 각 raw 호출과 입력을 검토하세요.

??를 사용하면 사용자가 선택한 아무 컬럼이나 허용해도 되나요?

??는 Knex raw 식별자 placeholder로 식별자를 인용하지만 선택 권한을 주지는 않습니다. 허용 목록으로 제한하세요.

참고 자료

함께 보기 SQL 인젝션(CWE-89): 동작 원리와 언어별 방어 방법 — flawopen.com MyBatis ${}와 #{}: SQL Injection 방지 MySQLi와 PDO: 안전한 Prepared Statement NHibernate는 SQL Injection을 막을 수 있나요? MongoDB NoSQL Injection: 안전한 쿼리 필터 숫자 ID도 문자열 포맷팅으로 SQL Injection이 발생할 수 있나요? 매개변수화 쿼리란 무엇인가