Re: Restrict EXPLAIN (ANALYZE) for RLS and security_barrier views

From: Laurenz Albe <laurenz(dot)albe(at)cybertec(dot)at>
To: Dean Rasheed <dean(dot)a(dot)rasheed(at)gmail(dot)com>
Cc: pgsql-hackers(at)lists(dot)postgresql(dot)org
Subject: Re: Restrict EXPLAIN (ANALYZE) for RLS and security_barrier views
Date: 2024-07-17 08:30:46
Message-ID: 80469229dd82a9124aaeea2a270448011ae0930b.camel@cybertec.at
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On Tue, 2024-07-16 at 18:36 +0100, Dean Rasheed wrote:
> On Mon, 6 May 2024 at 15:46, Laurenz Albe <laurenz(dot)albe(at)cybertec(dot)at> wrote:
> >
> > Currently, it is pretty easy to subvert the restrictions imposed
> > by row-level security and security_barrier views. All you have to
> > to is use EXPLAIN (ANALYZE) and see how many rows were filtered
> > out by the RLS policy or the view condition.
> >
> > This is not considered a security bug (I asked), but I still think
> > it should be fixed.
> >
> > My idea is to forbid EXPLAIN (ANALYZE) for ordinary users whenever
> > a statement uses either of these features.
>
> Hmm, but there are other ways to see how many rows were filtered out:
>
> - Use pg_stat_get_tuples_returned()

That is true, but it will only work if there is no concurrent DML activity
on the database. Still, I agree that it would be good to improve that,
for example by imposing a similar restriction on viewing these statistics.

> - Use pg_class.reltuples

I don't accept that. The estimated row count doesn't tell me anything
about the contents of the table.

> - Use the row estimates from a plain EXPLAIN

I don't buy that either. plain EXPLAIN will just tell you how many
rows PostgreSQL estimates for each node, and it won't tell you how
many rows will get filtered out by a RLS policy. Also, these are only
estimates.

> and probably more.
>
> Given that this isn't really a security bug, I think EXPLAIN should
> probably be left as-is. Otherwise, you'd have to go round closing all
> those other "holes" too.

The only reason this is not a security bug is because we document these
weaknesses of row-level security and security barrier views. I don't
think that should count as an argument against improving the situation.

With the exception of the table statistics you mention above, all the
other ways to derive knowledge about the "hidden" data leak very little
information, as does examining the query execution time (which is mentioned
in the documentation).

The information you can glean from EXPLAIN (ANALYZE) is much more
conclusive: "rows removed by filter: 1"

The patch that I am proposing certainly won't close all possibilities
to make an educated guess about "hidden" data, but it will close the
simplest way to reliably subvert RLS and security barrier views.

Is that not a worthy goal?
Shouldn't we plug the most glaring hole in PostgreSQL's data security
features?

I am aware that this change will make performance analysis more
cumbersome, but that's the price to pay for improved security.
I'd be ready to look at restricting pg_stat_get_tuples_returned(),
but perhaps that should be a separate patch.

Yours,
Laurenz Albe

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Dean Rasheed 2024-07-17 08:44:25 Re: New function normal_rand_array function to contrib/tablefunc.
Previous Message Pierrick Chovelon 2024-07-17 08:15:26 Re: Differents execution times with gin index, prepared statement and literals.