使用动态 SQL 函数中的参数进行通配符搜索

mg1*_*075 3 postgresql sql-injection dynamic-sql plpgsql

在使用动态 SQL 的函数中使用参数时,在 PostgreSQL 中实现通配符搜索的正确方法是什么?

作为起点,以下是 Erwin Brandstetter 在 stackoverflow 上回答不同问题的示例:

/sf/answers/843309421/

CREATE OR REPLACE FUNCTION report_get_countries_new (starts_with text
                                                   , ends_with   text = NULL)
RETURNS SETOF lookups.countries AS
$func$
DECLARE
   sql text := 'SELECT * FROM lookups.countries WHERE country_name >= $1';
BEGIN
   IF ends_with IS NOT NULL THEN
      sql := sql || ' AND country_name <= $2';
   END IF;

   RETURN QUERY EXECUTE sql
   USING starts_with, ends_with;
END
$func$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

假设country_name您想要进行前导和尾随通配符搜索。

例如,不使用参数,AND country_name LIKE '%ic%'.

在这种情况下,在否定 SQL 注入风险方面实现通配符搜索的最佳方法是什么?

Erw*_*ter 5

假设country_name您想要进行前导和尾随通配符搜索。

为此,您不需要动态 SQL。只是:

CREATE OR REPLACE FUNCTION report_get_countries_new (_pattern text)
  RETURNS SETOF lookups.countries AS
$func$
   SELECT *
   FROM   lookups.countries
   WHERE  country_name LIKE '%' || _pattern || '%'
$func$ LANGUAGE sql;
Run Code Online (Sandbox Code Playgroud)

称呼:

SELECT * FROM report_get_countries_new ('ic');  -- without wildcards!
Run Code Online (Sandbox Code Playgroud)

完全消除了 SQL 注入风险,因为它带有动态 SQL。

调用者仍然可以随意包含通配符(除非您处理参数以过滤通配符),但是有一个硬编码的前导通配符和一个尾随通配符(除非参数以\从尾随 中删除特殊含义而结束%)。

即使您使用动态 SQL 并且 EXECUTEPL/pgSQL,只要您使用以下子句将值作为传递,就不会有 SQL 注入的风险USING

有关的: