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

好家伙.....

首先,因为您复制到文件,您的函数必须以超级用户身份运行,并且您将用户提供的 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 回答