0

postgres で関数を作成していますが、奇妙なエラーが発生します。私は何を間違っていますか?私はまた、あなたの変種がそれを行う方法を見たいと思います

CREATE OR REPLACE FUNCTION export_csv(request TEXT, filename VARCHAR(255))
RETURNS VOID AS 
$$
BEGIN
  EXECUTE 'COPY (' || request || ') TO "/home/r90t/work/study/etl/postgres_etl/export/' || filename || '" WITH CSV;';
END
$$
LANGUAGE plpgsql;

リクエスト:

SELECT export_csv('SELECT * FROM orders', 'orders.csv')

エラー:

psql:/tmp/vUp267V/dbext.sql:2: ERROR:  syntax error at or near ""/home/r90t/work/study/etl/postgres_etl/export/orders.csv""
LINE 1: COPY (SELECT * FROM orders) TO "/home/r90t/work/study/etl/po...
                                   ^$
QUERY:  COPY (SELECT * FROM orders) TO "/home/r90t/work/study/etl/postgres_etl/export/orders.csv" WITH CSV;
CONTEXT:  PL/pgSQL function export_csv(text,character varying) line 3 at EXECUTE statement
4

1 に答える 1

0

ああ少年.....

まず、COPY TO FILE であるため、関数はスーパーユーザーとして実行する必要があり、ユーザーによって提供された SQL クエリをそのファイルにインライン化しています。少なくともスーパーユーザーとしてクエリを実行する必要があり、SECURITY DEFINER を設定していません。しかし、関数の要点は SQL インジェクションであり、利益はほとんどありません。これは個人的な研究のためのものだと思いますが、将来的にビジネスのデータを危険にさらすような方法でそれを行うことによって得られるものは何もありません.

特に、次のようなことをするとどうなるのだろうか。

 SELECT export_csv('SELECT * FROM ORDERS TO STDOUT; DROP DATABASE critical_db; --', 'foo');

また

 SELECT export_csv('SELECT * FROM ORDERS', '../../../../../../../var/lib/pgsql/data/log/postgresql-Tue.log');

本当に、本当に、あなたの関数では本当に悪いことが可能です。やらないでください。これらは現在封じ込められていますが、誰かが次のことを行うとすぐに、あなたは完全に:

 ALTER FUNCTION export_csv SET SECURITY DEFINER;

より良いアプローチは、引用してその場で処理できる単一の引数を取ることです。何かのようなもの:

CREATE OR REPLACE FUNCTION export_csv(relation name, columns name[])
RETURNS VOID AS 
$$
DECLARE column_list text;
BEGIN
  SELECT array_to_string(cols, ', ') INTO column_list
    FROM (SELECT array_agg(quote_literal(col)) as cols
            FROM unnest(columns) col
         ) a;

  EXECUTE 'COPY (SELECT ' || column_list || ' FROM ' || quote_ident(relation) || ') 
           TO ' || quote_literal('/home/r90t/work/study/etl/postgres_etl/export/' || relation) || ' WITH CSV;';
END
$$
LANGUAGE plpgsql;

これにより、SQL インジェクションに対する保護が得られます。最後に日付を追加する必要がある場合は、quote_literal 呼び出し内の何かでそれを行うことができます。

于 2013-11-26T05:06:42.153 に答える