PostgreSQL schema,database owner 的高危注意事项
背景
云用户反映的一个问题,引发一系列安全思考。
以下是创建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和超级用户能删对应的对象。