【问题标题】:Parameterized query in Postgresql with a json arrayPostgresql中带有json数组的参数化查询
【发布时间】:2016-05-11 10:22:20
【问题描述】:

我想使用参数化查询将 array_prepend 调用到 json[] 中。我正在使用 pg-promise npm 包,但这使用的是普通的 node-postgres 适配器。

我的查询是:

db.query(`update ${schema}.chats set messages =
  array_prepend('{"sender":"${sender}","tstamp":${lib.ustamp()},"body":$1}',messages) where chat_id = ${chat_id}`
 , message));

与“$1”相同。

它适用于非参数化查询。

以上代码产生:

{ [错误:“hiya”处或附近的语法错误]

这样做的主要原因是避免 sql 注入(文档说它们在使用参数化查询时会充分转义)。

【问题讨论】:

  • 1.确保升级到最新的 pg-promise; 2、将${schema}替换为${schema~},生成正确的SQL名称。另见:SQL Names
  • 我认为有一个混淆。 ${schema} 和所有其他 ${vars} 不是来自用户输入,并且是 es6 模板。将查询更改为 $1~ 可解决该错误。您能否确认此查询现在仅添加 $1~ 即可抵抗 sql 注入?谢谢
  • 您通过两次破坏格式得到了肯定的结果 - 第二个错误破坏了第一个错误,因此结果有效。你不应该使用这样的方法,它一直都是错误的。请参阅我在回答中提供的示例。
  • 是的,你太快了 :)
  • 关于 SQL 注入的问题。如果您使用标准变量注入查询值,而使用名称语法的 SQL 名称 - 正如我在回答中所展示的那样,那么您的所有字符串总是以引号结尾,并且您所有的 sql 名称都以双引号结尾,因此不可能在 SQL 注入的情况下改变查询。

标签: node.js postgresql node-postgres pg-promise


【解决方案1】:

您的查询中有 2 个问题。

第一个是您使用的是 ES6 模板字符串,同时还使用带有${propName} 语法的 sql 格式。

From the library's documentation:

命名参数使用语法 $*propName* 定义,其中 * 是以下任何一个开闭对:{}、()、[]、、//,因此您可以根据自己的喜好使用其中一个,但请记住,{} 也用于 ES6 模板字符串中的表达式。

因此,您要么从 ES6 模板字符串更改为标准字符串,要么只是切换到不同的变量语法,例如 $/propName/$[propName],这样您就可以避免冲突。

第二个问题正如我之前在 cmets 中指出的那样,在生成正确的 SQL 名称时,使用记录为 SQL Names 的内容。

以下是查询格式的更简洁方法:

db.query('update ${schema~}.chats set messages = array_prepend(${message}, messages) where chat_id = ${chatId}', {
        schema: 'your schema name',
        chatId: 'your chat id',
        message: {
            sender: 'set the sender here',
            tstamp: 'set the time you need',
            body: 'set the body as needed'
        }
    }
);

如果对您要执行的查询类型有疑问,查看它的最快方法是通过pgp.as.format(query, values),它会为您提供确切的查询字符串。

如果你仍然想将 ES6 模板字符串用于其他用途,那么你可以将字符串更改为:

`update $/schema~/.chats set messages = array_prepend($/message/, messages) where chat_id = $/chatId/`

这只是一个例子,语法很灵活。请记住不要使用 ES6 模板字符串格式化将值注入查询,因为 ES6 模板不知道如何正确格式化 JavaScript 类型以符合 PostgreSQL,只有库知道。

【讨论】:

  • 无论发件人输入什么作为正文,这个查询现在是否是 sql 注入证明?
  • 我刚才在您的问题下的评论中回答了这个问题 :) 是的,您的 body 是一个文本字符串,将始终包含在单引号内,这使其不受 SQL 注入的影响。 SQL 注入不能通过引用的值或引用的 SQL 名称来改变查询,只能通过打开的查询。所以如果你使用库提供的默认格式,你是安全的;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多