Re: seeking advices for function

From: Merlin Moncure <mmoncure(at)gmail(dot)com>
To: "Jean-Yves F(dot) Barbier" <12ukwn(at)gmail(dot)com>
Cc: pgsql-novice(at)postgresql(dot)org
Subject: Re: seeking advices for function
Date: 2011-06-22 20:07:16
Message-ID: BANLkTimFuLeT1np_nSYFMpcvLSkO+TuN_A@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-novice

On Wed, Jun 22, 2011 at 2:30 PM, Jean-Yves F. Barbier <12ukwn(at)gmail(dot)com> wrote:
> Hi list,
>
> I've got some questions about this function:
>
> =============================
> DROP FUNCTION tsttst(TEXT, TEXT, BOOLEAN, INT8, INT8, TEXT[]);
> CREATE FUNCTION tsttst(TEXT,         -- FQTN
>                       TEXT,         -- Ordering column
>                       BOOLEAN,      -- TRUE=ASC / FALSE=DESC
>                       INT8,         -- LIMIT
>                       INT8,         -- OFFSET
>                       TEXT[])       -- Columns' names array
> RETURNS SETOF RECORD AS $$
> DECLARE
>    usr         TEXT;
>    ord         TEXT;
>    collist     TEXT;
>    qry         TEXT;
> BEGIN
>    -- Retrieve real caller's name
>    usr := session_user;
>    -- First check for table SELECT privilege
>    IF NOT has_table_privilege(usr, $1, 'SELECT') THEN
>        -- If needed, check SELECT privilege per column
>        FOR i IN 1 .. array_length($6, 1) LOOP
>            IF NOT has_column_privilege(usr, $1, $6[i], 'SELECT') THEN
>                RAISE EXCEPTION 'FNCT: tsttst: Call forbidden';
>                -- ADD HERE LOGING IN TABLE security.alert
>                --   YEAH, BUT HOW TO AVOID security.alert NEW ROW BEING
>                --   VOIDED FROM A ROLLBACK ???
>            END IF;
>        END LOOP;
>    END IF;
>    -- Set ordering direction
>    IF $3 THEN
>        ord := 'ASC';
>    ELSE
>        ord := 'DESC';
>    END IF;
>    -- Construct columns full list
>    collist := array_to_string($6, ',');
>    -- Build query from input parms
>    qry = 'SELECT ' || collist || ' FROM ' || $1 || ' ORDER BY ' || $2 || ' '
>          || ord || ' LIMIT ' || $4 || ' OFFSET ' || $5 || ';';
>    -- Return the whole query
>    RETURN QUERY EXECUTE qry;
> END;
> $$ LANGUAGE plpgsql STABLE STRICT SECURITY DEFINER;
> =============================
>
> * Is it totally non-vulnerable to SQL injection?
>
> * I intend to use this kind of function for data I/O, as a replacement for
>  views in an ERP project.
>  Considering that overhead introduced by builtin SELECT privilege check is
>  far from negligible (from 110ns to 800ns, one row select) but on the other
>  hand that it could replace thousands views and that an ERP isn't an
>  application that generates hundreds queries per second.
>  Is it a good idea or not?
>
> * A big problem is the implementation of trespassing attempts loging (see
>  comment in function) which shouldn't be subject to the subsequent rollback;
>  how can I do that?
>
> Any constructive critics will be welcome.

I think it's much better to use the database log to record security
violations. Wrapping SQL with a function like this is going to be a
problem factory. For example, it's a total optimization fence if you
ever need to do something like join against your 'view'. IMO, it's a
total non-starter.

If you *must* log to a table in a view definition, or want to sneakily
hook custom behaviors to a view generally, you can do something like
this.

say your view is:
CREATE VIEW v as SELECT * FROM foo;

organize your plpgsql function like this:
CREATE FUNCTION priv_check(_view text) RETURNS bool AS
$$
BEGIN
IF NOT has_table_privilege(session_user, _view, 'SELECT') THEN
/* insert into log via dblink (see dblink docs) */
RAISE ...
END IF;

RETURN true;
END;
$$ LANGUAGE PLPGSQL;

now you can work up your view like this:
CREATE VIEW v as SELECT * FROM foo WHERE (SELECT priv_check('foo'));

I'm pretty sure postgres is going to be smart enough to run priv_check
only once per select from the view in all reasonable cases. dblink
remains the only way to emit records you want to keep from a
transaction that you want to roll back without recovering.

merlin

In response to

Responses

Browse pgsql-novice by date

  From Date Subject
Next Message Merlin Moncure 2011-06-22 20:13:46 Re: How to trap error: nextval: reached maximum value of sequence
Previous Message Jean-Yves F. Barbier 2011-06-22 19:30:31 seeking advices for function