FlawOpen

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

¿Knex.js es seguro frente a SQL Injection?

Guía de referencia
Respuesta breve

Imagina SQL como un formulario impreso: un binding pone la entrada en un campo de valor; la interpolación la pega a las instrucciones. El query builder de Knex y knex.raw(sql, bindings) separan los valores, pero los nombres de tablas y columnas son estructura SQL y requieren una lista permitida confiable.

?? es el marcador raw de identificador de Knex. Cita el identificador, pero no autoriza la elección; usa una lista permitida.
SEGURO — bindings y lista permitida
const query = knex.raw(
  `SELECT * FROM users WHERE id = ${userId}`
);
INSEGURO — SQL montado con la entrada
// La entrada se concatena al 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"
  );

// Mantén el valor separado de la sintaxis SQL.
knex.raw("SELECT * FROM users WHERE id = ?", [userId]);

Cómo protegen los bindings de Knex los valores

Métodos como .where(), .insert() y .select() separan valores del SQL generado. En expresiones raw, pasa los valores como bindings: knex.raw("... = ?", [value]). ? representa un valor y ??, un identificador. No interpoles entradas en una cadena SQL.

Los identificadores dinámicos requieren una lista permitida

Un binding no autoriza columnas, tablas, ordenaciones, operadores ni fragmentos SQL elegidos por el usuario. ?? cita un identificador, pero no decide si se debe permitir. Asocia la opción a una lista fija antes de usar .orderBy(); deja las palabras clave y operadores fijos en el código.

Cómo auditar consultas raw

Busca cada llamada a knex.raw() y revisa juntos la cadena SQL y sus bindings. Comprueba que los valores usan bindings y que los identificadores dinámicos proceden de una lista pequeña. Raw no implica vulnerabilidad; depende de cómo se construyan el SQL y las entradas.

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

Preguntas frecuentes

¿knex.raw() evita SQL Injection por sí solo?

No. Usa bindings para valores no confiables, por ejemplo knex.raw("... = ?", [value]). Interpolar un valor en la cadena lo convierte en parte del SQL. Revisa cada llamada raw y sus entradas.

¿Puedo usar ?? y aceptar cualquier columna elegida por el usuario?

?? es el marcador raw de identificador de Knex. Cita el identificador, pero no autoriza la elección; usa una lista permitida.

Referencias

Véase también Inyección SQL (CWE-89): cómo funciona y cómo evitarla en cada lenguaje — flawopen.com MyBatis ${} vs #{}: evitar SQL Injection MySQLi vs PDO: prepared statements seguros ¿NHibernate protege frente a SQL Injection? Inyección NoSQL en MongoDB: filtros seguros SQL Injection en IDs numéricos: ¿riesgo? ¿Qué es una consulta parametrizada?