【问题标题】:PostgreSQL Dollar-Quoted Strings Constants to Prevent SQL InjectionPostgreSQL 美元引号字符串常量以防止 SQL 注入
【发布时间】:2018-04-04 06:38:23
【问题描述】:

我可以使用 PostgreSQL 的美元引号字符串常量安全地防止 SQL 注入吗?

我知道处理动态查询的最佳方法是让它们在具有参数化查询的应用程序层中生成,这不是这个问题的内容。所有的业务逻辑都在存储过程中。

我有一个存储过程,它接受参数并生成查询、运行它、格式化结果并将其作为文本块返回。这个函数传递了一个表名、列名和 WHERE 参数。传递给函数的 WHERE 参数来自用户在数据库中输入的数据。我想确保对 sts 进行清理,以便构建的查询是安全的。

使用 PostgreSQLs Dollar-Quoted Strings Constants,我应该能够安全地清理除“ $$ ”之外的所有字符串输入。但是,如果我对 "$" 进行字符串替换以对其进行转义,我应该能够进行安全的字符串比较。

存储过程:

function_name(tablename text, colnames text[], whereparam text)
--Build dynamic query...

函数调用:

SELECT 
  function_name('tablename', ARRAY['col1', 'col2', 'col3'], 'AND replace(col1, ''$'', ''/$'') =  $$' || replace(alt_string_col, '$', '/$') || '$$ ')
FROM alttable
WHERE alt_id = 123;

查询生成:

SELECT col1, col2, col3 FROM tablename WHERE 1=1 AND replace(col1, '$', '/$') =  $$un/safe'user /$/$ data;$$

由于我在将 col1 字段与转义的用户数据进行比较之前对其进行转义,因此即使用户输入“un/safe'user $$ data;”也是如此在字段 alt_string_col 中,双美元符号不会中断查询并且比较通过。

这是在 PostgreSQL 存储过程中转义字符串的安全方法吗?

编辑1

感谢欧文·布兰德施泰特。为EXECUTE 使用USING 子句我正要创建一个可以像这样调用的函数:

SELECT function_name(
        'tablename',
        ARRAY['col1', 'col2', 'col3'], 
        ARRAY[' AND col1 =  $1 ', ' OR col2 = $5 '],
        quote_literal(alt_string_col)::text, --Text 1-4
        NULL::text,
        NULL::text,
        NULL::text,
        alt_active_col::boolean, --Bool 1-4
        NULL::boolean,
        NULL::boolean,
        NULL::boolean,
        NULL::integer, --Int 1-4
        NULL::integer,
        NULL::integer,
        NULL::integer
        )
FROM alttable 
WHERE alt_id = 123;

它为可以传入的 WHERE 子句提供了一些灵活性。

在存储过程中,EXECUTE 语句有类似的内容。

  FOR results IN EXECUTE(builtquery) USING 
    textParm1, 
    textParm2, 
    textParm3, 
    textParm4, 
    boolParm1, 
    boolParm2, 
    boolParm3, 
    boolParm4, 
    intParm1, 
    intParm2, 
    intParm3, 
    intParm4
  LOOP
    -- Do some stuff
  END LOOP;

【问题讨论】:

    标签: postgresql stored-procedures sql-injection sanitization


    【解决方案1】:

    使用quote_ident() 在连接标识符时防止SQL 注入。或者 format() 在 Postgres 9.1 或更高版本中。

    使用 plpgsql 代码中的USING clause for EXECUTE 传递。或者至少quote_literal()

    要确保表名存在(并在连接时自动在必要时被引用和模式限定),请使用special data type regclass

    有关使用 plpgsql 执行动态 SQL 的更多信息:

    从 PostgreSQL 9.0 开始,您还可以使用 anonymous code blocks with the DO statement 执行动态 SQL。

    【讨论】:

    • 我为EXECUTE 尝试了USING 子句,但你必须知道你传递了多少个WHERE 子句。在我的示例中它适用于 1,但是如果您有 3 个用于一个呼叫而 6 个用于另一个呼叫会怎样。我实际上是使用 ARRAY[] 来传递这些参数,因此我可以遍历每个参数并将其添加到 WHERE。我将进一步研究 quote_indent() 。谢谢
    • @bendiy:quote_ident() 用于标识符(表名、列名等),quote_literal() 用于值。还有一些余地,您可以使用来自USING 的参数附加多少个 WHERE 子句:添加您可能在子句中使用的 all 参数。如果不是所有这些最终都被使用,那也没问题。而且你知道你必须关心的最大参数数量,因为你知道外部函数的参数。
    • quote_literal() 似乎是我需要的,并导致更优雅:SELECT function_name('tablename', ARRAY['col1', 'col2', 'col3'], 'AND col1 = ' || quote_literal(alt_string_col)) FROM alttable WHERE alt_id = 123;
    • USING 具有额外的性能优势,因为不必将值转换为文本表示、引用和回退。这对于浮点数特别有用,您可以在不以这种方式处理的情况下保持精度。
    猜你喜欢
    • 2012-03-05
    • 1970-01-01
    • 2010-12-21
    • 1970-01-01
    • 2015-07-22
    • 1970-01-01
    • 2020-09-28
    • 1970-01-01
    • 2011-09-26
    相关资源
    最近更新 更多