PostgreSQL schema,database owner 的高危注意事项

1 minute read

背景

云用户反映的一个问题,引发一系列安全思考。

以下是创建PostgreSQL schema的语法说明页的一个note:

http://www.postgresql.org/docs/9.5/static/sql-createschema.html

According to the SQL standard, the owner of a schema always owns all objects within it.   
PostgreSQL allows schemas to contain objects owned by users other than the schema owner.   
This can happen only if the schema owner grants the CREATE privilege on his schema to someone else, or a superuser chooses to create objects in it.    

schema的owner默认是该schema下的所有对象的owner。

同时PostgreSQL还允许用户在别人的schema下创建对象,所以一个对象可能属于”两个”owner。

更”糟糕”的是schema 的owner有 drop该schema下面的所有对象的权限。

所以千万不要把自己的对象创建到别人的schema下面,那很危险。

看个例子,

r1创建了一个schema r1, 并把这个schema的写权限给了r2。

然后r2和超级用户postgres分别在r1这个schema下面创建了一个表。

然后r1可以把r2和postgres在r1 schema下创建的表删掉,然后就没有然后了。

postgres=# create role r1 login;  
CREATE ROLE  
postgres=# create role r2 login;  
CREATE ROLE  
  
postgres=# grant all on database postgres to r1;  
GRANT  
postgres=# grant all on database postgres to r2;  
GRANT  
  
postgres=# \c postgres r1;  
postgres=> create schema r1;  
CREATE SCHEMA  
postgres=> grant all on schema r1 to r2;  
GRANT  
  
postgres=> \c postgres r2;  
postgres=> create table r1.t(id int);  
CREATE TABLE  
  
postgres=> \c postgres postgres  
postgres=# create table r1.t1(id int);  
CREATE TABLE  
  
postgres=# \c postgres r1  
postgres=> drop table r1.t;  
DROP TABLE  
postgres=> drop table r1.t1;  
DROP TABLE  
  
或者直接drop schema cascade来删除整个schema.    

对于database的owner也存在这个问题,它同样具有删除database中任何其他用户创建的对象的权力。

例子:

普通用户r1创建的数据库  
postgres=> \c postgres r1  
You are now connected to database "postgres" as user "r1".  
postgres=> create database db1;  
CREATE DATABASE  
postgres=> grant all on database db1 to r2;  
GRANT  
  
其他用户在这个数据库中创建对象  
postgres=> \c db1 r2  
You are now connected to database "db1" as user "r2".  
db1=> create schema r2;  
CREATE SCHEMA  
db1=> create table r2.t(id int);  
CREATE TABLE  
db1=> insert into t select generate_series(1,100);  
INSERT 0 100  
  
db1=> \c db1 postgres  
You are now connected to database "db1" as user "postgres".  
db1=# create table t(id int);  
CREATE TABLE  
db1=# insert into t select generate_series(1,100);  
INSERT 0 100  
  
数据库的OWNER不能直接删数据库中的对象  
postgres=> \c db1 r1  
You are now connected to database "db1" as user "r1".  
db1=> drop table r2.t ;  
ERROR:  permission denied for schema r2  
db1=> drop table public.t ;  
ERROR:  must be owner of relation t  
db1=> drop schema r2;  
ERROR:  must be owner of schema r2  
db1=> drop schema public;  
ERROR:  must be owner of schema public  
db1=> \c postgres r1  
You are now connected to database "postgres" as user "r1".  
postgres=> drop database r1;  
ERROR:  database "r1" does not exist  
  
但是可以直接删库  
postgres=> drop database db1;  
DROP DATABASE  

建议社区可以改进一下这个权限管理的风格:

例如drop schema时,如果发现schema里面有不属于当前schema owner的对象,则发出警告,并且不删除,另外加一个语法, 支持force, 发出notice并删除之。

对于drop database也是这样。

安全建议

介于此,我建议用户使用超级用户创建schema和database,然后再把schema和database的读写权限给普通用户,这样就不怕被误删了。因为超级用户本来就有所有权限。

还有一种方法是创建事件触发器,当执行drop 命令时,只有owner和超级用户能删对应的对象。

Flag Counter

digoal’s 大量PostgreSQL文章入口