这居然开放给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.
会发生什么
我们有一个函数可以构建一些 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.