如何编写一个 SQL 查询来安全地将记录插入到变量 table 名称中?

How do I write an SQL query that will safely insert a record into a variable table name?

我有一个函数可以将记录插入 table。 table的名字需要作为函数的参数,列名是动态获取的。为了防止 SQL 注入,我想使用 PostgreSQL 的参数化查询。像这样:

function insert(tableName, val1, val2) {
    let qry =   `INSERT INTO  (, )
                VALUES (, )
                RETURNING id;`

    let values = [tableName, 'col1', 'col2', val1, val2]

    return db.query(qry, values);
}

虽然 $n 替换对值非常有效,但它不能用于 table 或列标识符。

来自PostgreSQL documention

Arguments to the SQL function are referenced in the function body using the syntax $n: refers to the first argument, to the second, and so on. If an argument is of a composite type, then the dot notation, e.g., .name, can be used to access attributes of the argument. The arguments can only be used as data values, not as identifiers



将此与以下代码进行比较,该代码有效但似乎对 SQL 注入几乎没有提供保护。

(注意使用 ECMA6 ${} 字符串替换代替参数替换)

function insert(tableName, val1, val2) {

    let values = ['col1', 'col2', val1, val2]
    let qry =   `INSERT INTO ${tableName} (${values[0]}, ${values[1]})
                VALUES (, )
                RETURNING id;`


    return db.query(qry, values);
}


有没有办法允许参数化查询来缓解这种情况?我希望在 PostgreSQL 或 Node 的 Postgres 库中内置一些东西,但我会接受任何可靠的答案。

我是 运行 Node 9.4 和 PostgreSQL 10

一个选项是在继续之前使用参数从可用 table 列表中检查 table 名称。

我不确定是否有更简单的方法来传输变量,但是如果您将值放入临时 table,并调用从临时 [=14= 中获取值的过程], 将它们插入动态选择的 table 你应该是相当安全的。

好吧,对于这种情况,我想建议对象关系映射 (ORM),这是我个人的建议,也许这会对您有所帮助

here is a library link objection which you can use.

Objection.js 建立在名为 knex 的 SQL 查询生成器上。

这样你就可以编写一个干净的语法

here is very simple example

// personPerson 模型的实例。

const movie = await person
  .$relatedQuery('movies')
  .insert({name: 'The room', awesomeness: 9001});

console.log('best movie ever was added');

insert into "Movie" ("name") values ('The room')

如果你有以下参数:

  • table - 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 注入。