On Tue, Jun 10, 2014 at 7:18 PM, Craig Ringer <cr...@2ndquadrant.com> wrote:
> On 06/11/2014 02:19 AM, Tom Lane wrote:
>> Hm ... I'm not following why we'd need a special case for superusers and
>> not anyone else?  Seems like any useful RLS scheme is going to require
>> more privilege levels than just superuser and not-superuser.
> What it really needs is to invalidate plans when switching between
> RLS-enabled and RLS-exempt users, yes. I'm sure we'll want an "RLS
> exempt" right or mode sooner rather than later, so I'm against tying
> this explicitly to superuser as such.
> I wouldn't be surprised to see
> down the track, with a right controlling whether you can or not. Or at
> least, a right that directly exempts a user from row security.

I'm really concerned about the security implications of this patch.  I
think we're setting ourselves up for a whole lot of hurt for somewhat
unclear gain.

In my view, commit 842faa714c0454d67e523f5a0b6df6500e9bc1a5 basically
*is* row-level security: instead of applying a row-level security
policy to a table, just create a security-barrier view over the table
and grant access to the view.  Forget that the table ever existed.

With this approach, there's a lot of stuff that we don't have to
reinvent.  We've talked a lot about whether row-level security should
only be concerned with the rows it scans, or whether it should also
restrict the new rows that can be created.  You can get either
behavior by choosing whether or not to use WITH CHECK OPTION.  And
then there's this question of who should be RLS-exempt; that's
basically a question of to whom you grant privileges on the underlying
table.  Note that this can be very fine-grained: for example, you can
allow someone to exempt themselves for selects but not for updates by
granting them SELECT privileges but not UPDATE privileges on the
underlying table.  And potentially-exempt users can choose whether
they want a particular access to actually be exempt by targeting the
view when they don't want to be exempt and the table when they do.
That's mighty useful for debugging, at least IMHO.  And, if you want
to have several row-level security policies for different classes of
users, just create more than one view and grant different privileges
on each.

By contrast, it seems to me that every design so far proposed for
something that is actually called row-level security - as opposed to
commit 842faa714c0454d67e523f5a0b6df6500e9bc1a5, which *really is*
row-level security, is extremely limited.  Look back at all the things
listed in the previous paragraph; can you do those things easily with
the designs that have been proposed?  As far as I can see, not really.
Your (Craig's) rls-9.4-upd-sb-views patch seems to have a rough
equivalent of WITH CHECK OPTION, probably because we've talked a lot
about that specific issue, but it doesn't line up exactly to what WITH
CHECK OPTION actually does.  There's no independently-grantable
RLS-exemption privilege - and even when we talk about that, it's
usually some kind of global bit that applies to all tables and all
operations equally - whereas with the above approach it can be
per-table and per-operation and doesn't require superuser intervention
to flip the bit.  There's no way for users who are RLS exempt to turn
off their exemption for testing purposes, let alone on a per-table
basis.  There's no way to have multiple RLS policies on a single
table.  All of those are things that we get "for free" in the
view-over-table model, and implementing formal RLS basically requires
us to either invent a new RLS-specific way of doing each of those
things, or suffer along with a subset of the functionality.  Yuck.

But what's really awful about this whole design is that it breaks the
invariant that reading from a table doesn't run anybody else's code.
It's already the case that users need to be awfully careful about
modifying tables, because that might fire triggers that do bad things.
But at least you can SELECT from a table and it will either work, or
it will fail with a permission denied error.  What it will not do is
unexpectedly run some code that you weren't expecting it to run.  You
can't be so blithe about selecting from views, but reading a plain
table is always OK.  Now, as soon as we introduce the concept that
selecting from a table might not really mean "read from the table" but
"read from the table after applying this owner-specified qual", we're
opening up a whole new set of attack surfaces.  Every pg_dump is an
opportunity to hack somebody else's account, or at least audit their
activity.  Protecting the superuser against everybody else is nice,
but I think it's just as important to protect non-superusers against
each other, and I think that's going to be hard -- because in the RLS
world, SELECT * FROM tab is now *fundamentally* ambiguous.  Maybe it's
reading from the table, and maybe it's really clandestinely reading
from a view over the table, and the user has no way of being really
clear about which behavior they want.  From a security point of view,
that seems very bad.

To recap:

1. Reinventing RLS-specific ways to do all of the things that can
already be done in the view-over-table model is a lot of work.
2. There's a danger that the functionality available in the two models
will diverge, so that certain things can only be done in one world or
the other.
3. On the whole, it seems likely that the RLS-specific world will
remain impoverished compared to the view-over-table model.
4. Making SELECT * FROM tab ambiguous seems likely to be a security minefield.

Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:

Reply via email to