我有一个向表中插入记录的函数。表名需要作为函数的参数,列名是动态获取的。为了防止 SQL 注入(inject),我想使用 PostgreSQL 的参数化查询。像这样:
function insert(tableName, val1, val2) {
let qry = `INSERT INTO $1 ($2, $3)
VALUES ($4, $5)
RETURNING id;`
let values = [tableName, 'col1', 'col2', val1, val2]
return db.query(qry, values);
}
虽然 $n
替换对值非常有效,但它不能用于表或列标识符。
Arguments to the SQL function are referenced in the function body using the syntax $n: $1 refers to the first argument, $2 to the second, and so on. If an argument is of a composite type, then the dot notation, e.g., $1.name, can be used to access attributes of the argument. The arguments can only be used as data values, not as identifiers
将此与以下代码进行比较,该代码有效但似乎对 SQL 注入(inject)几乎没有提供保护。
(注意使用 ECMA6 ${}
字符串替换代替参数替换)
function insert(tableName, val1, val2) {
let values = ['col1', 'col2', val1, val2]
let qry = `INSERT INTO ${tableName} (${values[0]}, ${values[1]})
VALUES ($3, $4)
RETURNING id;`
return db.query(qry, values);
}
有没有办法允许参数化查询来缓解这种情况?我希望在 PostgreSQL 或 Node 的 Postgres 库中内置一些东西,但我会接受任何可靠的答案。
我正在运行 Node 9.4 和 PostgreSQL 10
最佳答案
如果你有以下参数:
table
- 表名columns
- 列名数组或具有属性的对象values
- 对应列值的数组
然后是pg-promise中最简单的方法语法如下:
function insert(table, columns, values) {
const query = 'INSERT INTO ${table:name} (${columns:name}) VALUES(${values:csv})';
return db.query(query, {table, columns, values});
}
或更短的语法:
function insert(table, columns, values) {
const query = 'INSERT INTO ${table~} (${columns~}) VALUES(${values:csv})';
return db.query(query, {table, columns, values});
}
参见 SQL Names , CSV Filter .
从 7.5.0 版本开始,动态对象变得更加简单:
function insert(table, obj) {
const query = 'INSERT INTO ${table:name} (${obj:name}) VALUES(${obj:csv})';
return db.query(query, {table, obj});
}
Under SQL Names, the first example shows how a column name can be inserted dynamically. Is this insertion something that is done by your library, or does the replacement happen on the Postgres side?
PostgreSQL 服务器不允许动态 SQL 名称,pg-promise在内部实现它,提供安全转义以防止 SQL 注入(inject)。
关于javascript - 如何编写 SQL 查询以安全地将记录插入可变表名?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48719334/