PostgreSQL:LISTEN的参数替换?

时间:2018-11-21 00:03:28

标签: postgresql security sql-injection

常识表明,SQL查询字符串应该绝对不要手工组装。因此,所有数据库接口都提供参数替换,所有用户都可以使用它,无一例外。*

我正在使用PostgreSQL v10.5,nodejs v8.12.0,node-postgres 7.6.1。

对于SELECT语句,参数替换可以正常工作:

> await db.query("select from users where id = 'mic'");
(success, 1 row returned)
> await db.query("select from users where id = $1", ["mic"]);
(success, 1 row returned)

但这不适用于LISTEN语句:

> await db.query("listen topicname");
(success)
> await db.query("listen $1", ["topicname"]);
(error: syntax error at or near "$1")

我想听的主题名称是动态的。它来自不可靠的半可靠来源,这些来源不应由用户控制。但是,为什么要违背所有既定的最佳实践并抓住任何机会呢?

不幸的是,从我的测试中,我担心PostgreSQL根本无法为LISTEN查询做参数替换。

对此有任何解决方案或解决方法吗?

*)仅在某些未来的未来社会中这种说法才是正确的。

2 个答案:

答案 0 :(得分:1)

您是正确的,这无法在PostgreSQL中完成。

作为一种解决方法,编写一个使用dynamic SQL的PL / pgSQL函数,如下所示:

EXECUTE format('LISTEN %L', topicname);

format函数可以正确地转义字符串;在这种情况下,%L格式会产生适当的带引号的字符串 L iteral。

答案 1 :(得分:1)

我没有足够的声誉来评论答案,但是建议的解决方案对我不起作用。 使用%L会产生带引号的字符串,这会导致以下错误:

ERROR: syntax error at or near "'topic'"

应该改为使用%I格式(SQL标识符,已记录为表和列名,但它也适用于通道名)。您也可以使用quote_ident函数。请参阅有关创建动态查询here的文档。

以下PL / pgSQL函数对我们有用:

CREATE OR REPLACE FUNCTION listenForChannel(
    channel_   TEXT
) RETURNS VOID AS $$
BEGIN
    EXECUTE format('LISTEN %I', channel_);
END
$$ LANGUAGE PLPGSQL;