问题
I am building a JSON API in Ruby on Rails. I want to have write-only user accounts that are supposed to feed data to the system but who should not be allowed to read from it.
In order to achieve an extra layer of security, I'd like to enforce this rule at the database level.
The idea is to have a "writer" type of user which uses a separate connection to the database. This connection should be allowed to insert / update / delete but not to select.
I have everything set up nicely but unfortunately Rails generates this query upon insert:
INSERT INTO "default"."products" ("id", "name", "sku") VALUES ($1, $2, $3) RETURNING "id"
The "RETURNING id" part is making it fail because the user does not have SELECT permissions:
ActiveRecord::StatementInvalid: PG::InsufficientPrivilege: ERROR: permission denied
for relation products:
INSERT INTO "default"."products" ("id", "name", "sku") VALUES ($1, $2, $3) RETURNING "id"
Is there any way to get around this in PG or Rails? The two options I see are:
- Granting a "limited" SELECT permission to writer users in PG, so they can only "see" some columns. I don't know if this is possible at all.
- Getting Rails to not add that "RETURNING id" at the end of the query, although this might have side effects.
I found one article of someone who had the same issue and ended up just granting SELECT rights to writer users:
https://til.hashrocket.com/posts/0c83645c03-postgres-permissions-to-insert-but-not-return
Any chance there is an actual solution to get the setup above to work?
回答1:
There is a way using row level security feature available since PostgreSQL 9.5:
create table products(id serial primary key, name text not null, sku text not null);
grant select,insert on products to tometzky;
grant usage on sequence products_id_seq to tometzky;
alter table products enable row level security;
create policy products_tometzky on products to tometzky
using (id=currval('products_id_seq'));
tometzky=> select * from products;
ERROR: currval of sequence "products_id_seq" is not yet defined in this session
tometzky=> insert into products (name, sku) values ('a','a') returning id;
1
tometzky=> select * from products;
1|a|a
tometzky=> insert into products (name, sku) values ('b','b') returning id;
2
tometzky=> select * from products;
2|b|b
A user only sees the last row he put to the database. He knows what it is anyway.
来源:https://stackoverflow.com/questions/43641326/postgresql-rails-is-it-possible-to-have-a-write-only-database-user-in-pg