Константы PostgreSQL, заключенные в доллары, для предотвращения SQL-инъекций - PullRequest
4 голосов
/ 19 ноября 2011

Могу ли я безопасно предотвратить SQL-инъекцию, используя строковые константы PostgreSQL, заключенные в доллары?

Я знаю, что лучше всего обрабатывать динамические запросы, если их генерировать на уровне приложения с параметризованным запросом, это не то, чтовопрос о.Вся бизнес-логика в хранимых процедурах.

У меня есть хранимая процедура, которая принимает параметры и генерирует запрос, выполняет его, форматирует результаты и возвращает его в виде фрагмента текста.Этой функции передаются имя таблицы, имена столбцов и параметры WHERE.Параметры WHERE, передаваемые в функцию, взяты из введенных пользователем данных в базе данных.Я хотел бы убедиться, что строки очищены, поэтому построенный запрос является безопасным.

Используя строковые константы в кавычках PostgreSQLs, я должен быть в состоянии безопасно санировать весь ввод строки, кроме '$$',Однако, если я заменю строку на «$», чтобы избежать ее, я смогу выполнить безопасное сравнение строк.

Хранимая процедура:

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?

Edit1

Спасибо Эрвину Брандштеттеру.Используя предложение USING для EXECUTE, я собирался создать функцию, которая может быть вызвана следующим образом:

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;

1 Ответ

4 голосов
/ 19 ноября 2011

Используйте quote_ident() для защиты от внедрения SQL при объединении идентификаторов .Или format() в Postgres 9.1 или новее.

Используйте предложение USING для EXECUTE в коде plpgsql для передачи значений ,Или, по крайней мере, quote_literal().

Чтобы убедиться, что имя таблицы существует (и при необходимости объединяется в кавычки и уточняется схемой при необходимости), используйте специальный тип данных regclass.

Подробнее о выполнении динамического SQL с помощью plpgsql:

Начиная с PostgreSQL 9.0, вы также можете использовать блоки анонимного кода с оператором DO для выполнения динамического SQL.

...