如何编写可以安全地将记录插入变量表名的SQL查询?

时间:2018-02-10 09:41:41

标签: javascript sql node.js postgresql sql-injection

我有一个将记录插入表中的函数。表的名称必须是函数的参数,并且列名是动态获取的。为了防止SQL注入,我想使用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替换对值很有用,但它不能用于表或列标识符。

来自PostgreSQL documention

  

使用语法$ n在函数体中引用SQL函数的参数:$ 1表示第一个参数,$ 2表示第二个参数,依此类推。如果参数是复合类型,则点符号(例如$ 1.name)可用于访问参数的属性。参数只能用作数据值,而不能用作标识符


将此与以下代码进行比较,该代码可以正常运行但似乎没有提供针对SQL注入的保护。

(注意使用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或Postgres库中内置Node,但我会接受任何可靠的答案。

我正在运行Node 9.4和PostgreSQL 10

3 个答案:

答案 0 :(得分:1)

如果您有以下参数:

  • 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 NamesCSV 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});
}
  

SQL Names下,第一个示例显示了如何动态插入列名。这个插件是由您的库完成的,还是替换发生在Postgres端?

PostgreSQL服务器不允许动态SQL名称,pg-promise在内部实现它,提供安全转义以防止SQL注入。

答案 1 :(得分:0)

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

我不确定是否有更简单的方法来传输变量,但如果将值放入临时表中,并调用有关从临时表中获取值的过程,请将这些值插入到动态选择的表中,相当安全。

答案 2 :(得分:0)

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

  

这是一个图书馆链接   你可以objection   使用

Objection.js构建于名为knex的SQL查询构建器上。

那么你可以写一个干净的语法

  

这是一个非常简单的例子

// 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')