flawopen.com/JavaScript 中的 SQL 注入/Knex.js
Knex.js 能防止 SQL 注入吗?
参考指南
简答
把 SQL 想成印好的表格:binding 将输入放入值栏;字符串插值则把它粘进指令。Knex 查询构建器和knex.raw(sql, bindings)会分离值,但表名和列名属于 SQL 结构,必须通过可信允许列表选择。
??是 Knex 的 raw 标识符占位符,会引用标识符而非绑定数据值;仍需用允许列表限制可选项。安全 — 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();关键字和运算符固定在代码中。
如何审查 raw 查询
搜索每个knex.raw()调用,并一起检查 SQL 字符串和 bindings。数据值应通过 bindings 传入,动态标识符应来自小型允许列表。raw 查询不一定有漏洞;关键在于 SQL 文本和输入的构造方式。
rg -n 'knex\.raw\(' -g '*.js' -g '*.ts' -g '*.mjs' -g '*.cjs' .常见问题
knex.raw() 本身能阻止 SQL 注入吗?
不能。使用 bindings 可安全处理不可信值,例如knex.raw("... = ?", [value])。将值插入 SQL 字符串会使其成为 SQL 源码的一部分。请检查每个 raw 调用及输入。
使用 ?? 后可以接受用户选择的任意列吗?
??是 Knex 的 raw 标识符占位符,会引用标识符而非绑定数据值;仍需用允许列表限制可选项。