Postgres功能错误

时间:2013-10-10 09:31:45

标签: function postgresql csv

我正在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;

REQUEST:

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

ERROR:

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

1 个答案:

答案 0 :(得分: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调用中的内容来做到这一点。