这居然开放给SQL注入?

Is this actually open to SQL injection?

我们有一个函数可以构建一些 XML 并使用 EXECUTE/USING 来尝试防止 SQL 注入。它是这样的:

CREATE OR REPLACE FUNCTION public.f1(t TEXT)
    RETURNS XML AS
$BODY$
DECLARE
    ret_val XML;
BEGIN
    EXECUTE 'SELECT ''<'' ||  || ''>'''
    --rest of xml building
    INTO ret_val
    USING t;
    RETURN ret_val;
END
$BODY$
    LANGUAGE plpgsql IMMUTABLE;

由于串联,我不太喜欢。如果我们可以只做 SELECT '''<>'' 会好得多,但最终会得到一个文字 $1 而不是用值替换它。

由于串联,这让我想知道我们是否需要 SQL 注入预防。它不是从 table 中读取,只是构建一个返回的 XML 字符串。

在这种情况下不使用 USING 是否存在任何实际风险?连接 $1 会否定 USING 的影响,还是 USING 甚至对不使用 table 的语句有任何影响?

这里SQL注入没有危险,因为你用的是USING.

请注意,您可以使用静态 SQL 来实现相同的目的:

SELECT '<' || t || '>' INTO ret_val;

这里有一些东西要打开。

首先,你的SQL实际上是一个固定的字符串:

'SELECT ''<'' ||  || ''>'''

所以这里不能直接注入任何东西,因为没有动态SQL。正如 Laurenz Albe 指出的那样,这个特定示例中的 SQL 可以写成非动态语句:

SELECT '<' || t || '>'

这里仍然没有SQL注入,因为你不是评估t的内容,只是将它作为一个字符串来操作,只是因为 SELECT a + 1 会将 a 作为一个数字来处理。

重点是实际的SQL是硬编码的,拼接只是那个SQL.

中的指令

请注意,这个看起来相似的查询 是危险的(语法突出显示提供了区别的线索):

EXECUTE 'SELECT ''<' || t || '>''' -- DON'T DO THIS!

此处,t 的值被用作 作为 SQL 字符串的一部分 - 连接首先发生,然后执行结果。因此 '1'; DROP TABLE users; --' 的值将导致查询 SELECT '<1'; DROP TABLE users; --,这显然是不可取的。

其次,作为 explained in the docs</code> 是一个 <em> 参数 </em>,由 <code>USING 子句提供 作为数据,因此它也不会受到 SQL 注入的影响。这类似于在数据库外的编程语言中使用参数化查询 - 您将查询构建为字符串,仔细地将引用的表和列列入白名单,然后单独提供可变数据,其中不能将其重新解释为 SQL.或者换句话说,它就像另一个函数 "one level deeper",USING 子句指定的参数就像实际函数的参数一样。

最后,请注意:您 容易受到 XML 注入:如果没有其他验证或转义 t,您可能会生成无效或危险的 XML。例如,考虑如果 t 的值为 'foo><script>alert("Hello, world!");</script></foo' 并且结果最终被解析为 HTML.

会发生什么