为什么允许新用户创建表?

and*_*s-h 60 postgresql permissions postgresql-9.2

我想知道为什么允许新创建的用户在连接到数据库后创建表。我有一个数据库,project2_core

postgres=# \l
                                          List of databases
     Name      |    Owner     | Encoding  |   Collate   |    Ctype    |       Access privileges       
---------------+--------------+-----------+-------------+-------------+-------------------------------
 postgres      | postgres     | SQL_ASCII | C           | C           | 
 project2_core | atm_project2 | UTF8      | de_DE.UTF-8 | de_DE.UTF-8 | project2=CTc/project2
 template0     | postgres     | SQL_ASCII | C           | C           | =c/postgres                  +
               |              |           |             |             | postgres=CTc/postgres
 template1     | postgres     | SQL_ASCII | C           | C           | =c/postgres                  +
               |              |           |             |             | postgres=CTc/postgres
(5 rows)
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好。现在我创建一个用户:

postgres=# CREATE ROLE dietrich ENCRYPTED PASSWORD 'md5XXX' LOGIN NOCREATEROLE NOCREATEDB NOSUPERUSER
Run Code Online (Sandbox Code Playgroud)

好的。当我尝试连接到数据库时,不允许用户这样做:

$ psql -h localhost -p 5432 -U dietrich -W project2_core
Password for user dietrich: 
psql: FATAL:  permission denied for database "project2_core"
DETAIL:  User does not have CONNECT privilege.
Run Code Online (Sandbox Code Playgroud)

这是我所期望的。现在奇怪的事情开始了。我授予用户CONNECT

postgres=# GRANT CONNECT ON DATABASE project2_core TO dietrich;
GRANT
postgres=# \l
                                          List of databases
     Name      |    Owner     | Encoding  |   Collate   |    Ctype    |       Access privileges       
---------------+--------------+-----------+-------------+-------------+-------------------------------
 postgres      | postgres     | SQL_ASCII | C           | C           | 
 project2_core | atm_project2 | UTF8      | de_DE.UTF-8 | de_DE.UTF-8 | project2=CTc/project2+
               |              |           |             |             | dietrich=c/project2
 template0     | postgres     | SQL_ASCII | C           | C           | =c/postgres                  +
               |              |           |             |             | postgres=CTc/postgres
 template1     | postgres     | SQL_ASCII | C           | C           | =c/postgres                  +
               |              |           |             |             | postgres=CTc/postgres
(5 rows)
Run Code Online (Sandbox Code Playgroud)

无需任何进一步授权,用户就可以创建一个表:

$ psql -h localhost -p 5432 -U dietrich -W project2_core
Password for user dietrich: 
psql (9.2.3)
SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256)
Type "help" for help.

project2_core=> create table adsf ();
CREATE TABLE
project2_core=> \d
        List of relations
 Schema | Name | Type  |  Owner   
--------+------+-------+----------
 public | adsf | table | dietrich
(1 row)
Run Code Online (Sandbox Code Playgroud)

我本以为在我明确做之前不允许用户做任何事情 GRANT USAGE对架构然后GRANT SELECT在表上。

我的错误在哪里?我究竟做错了什么?我怎样才能实现我想要的(在明确授予她适当的权限之前不允许新用户做任何事情。

我迷路了,非常感谢您的帮助:)

编辑按照@daniel-verite 的建议,我现在在创建数据库后立即撤销所有内容。不允许用户dietrich再创建表。好的。但是:现在,数据库的所有者project2也不允许创建表。即使在发出GRANT ALL PRIVILEGES ON DATABASE project2_core TO project2and 之后GRANT ALL PRIVILEGES ON SCHEMA public TO project2,我也收到错误ERROR: no schema has been selected to create in,当我特别尝试时CREATE TABLE public.WHATEVER ();,我收到ERROR: permission denied for schema public。我究竟做错了什么?

Dan*_*ité 59

创建新数据库时,任何角色都可以在public架构中创建对象。要消除这种可能性,您可以在创建数据库后立即发出:

REVOKE ALL ON schema public FROM public;
Run Code Online (Sandbox Code Playgroud)

编辑:执行上述命令后,只有超级用户可以在public架构内创建新对象,这是不切实际的。假设foo_user应授予非超级用户此权限,则应通过以下方式完成:

GRANT ALL ON schema public TO foo_user;
Run Code Online (Sandbox Code Playgroud)

要了解ALL模式的含义,我们必须参考文档中的 GRANT(在 PG 9.2 中,有不少于 14 种形式的 GRANT 语句适用于不同的事物......)。似乎对于模式来说,它意味着CREATEUSAGE

另一方面,GRANT ALL PRIVILEGES ON DATABASE...将授予CONNECTCREATETEMP,但是CREATE在此上下文中涉及模式,而不是永久表。

关于此错误:ERROR: no schema has been selected to create in,当尝试创建没有架构限定的对象(如 中create table foo(...))而缺乏在search_path.


Cra*_*ger 25

了解这里的关键一点是特权不是heirachical,并且不含有对象继承ALL表示此对象的所有权限,而不是此对象和所有包含的对象的所有权限

当您授予ALL数据库时,您授予CREATE, CONNECT, TEMP. 这些是对数据库对象本身的操作:

  • CONNECT: 连接到数据库
  • CREATE:创建架构不是表)
  • TEMP: 创建临时对象,包括但不限于临时表

现在,默认情况下,每个 PostgreSQL 数据库都有一个public在创建数据库时创建的架构。此模式具有授予角色的所有权限public,每个人都是角色的隐式成员。对于模式,ALL意味着CREATE, USAGE

  • CREATE: 在这个模式中创建对象(包括表)
  • USAGE: 列出架构中的对象并在其权限允许的情况下访问它们

如果您没有指定架构来创建像表这样的对象,则数据库引擎使用search_path,默认情况下public架构首先在 上,search_path因此在那里创建表。public默认情况下每个人都有权限,因此允许创建。用户对数据库的权限在这一点上无关紧要,因为用户并没有试图对数据库对象本身做任何事情,只是在其中的一个模式。

除了授予用户之外,您没有授予用户任何权利都没有关系 CONNECT对数据库的,因为public默认情况下架构允许所有用户在其中创建表。Daniel 已经解释了如何根据需要撤销该权利。

如果您想显式地委派每项权利,请从 public 中撤销所有权限,或者简单地删除 public 模式。如果需要,您可以创建一个应用此更改的新模板数据库。或者,您可以将其应用于template1,但这可能会破坏许多假设的第 3 方代码public存在且可写。


如果您查看文件系统类比,这可能更有意义。

如果我有目录结构(模式简化为仅显示适用于当前用户的模式):

/dir1           mode=r-x
/dir1/dir2      mode=rwx
Run Code Online (Sandbox Code Playgroud)

那么我不能在 内创建任何东西/dir1,因为我没有写权限。所以如果我touch /dir1/somefile会收到一个权限被拒绝的错误。

但是,我确实有权查看内部/dir1并访问包含的文件和目录,包括/dir1/dir2. 我有写权限dir2。所以touch /dir1/dir2/somefile成功,即使我没有写权限dir1

数据库和模式也是如此。


小智 9

如果只想阻止新用户创建表,则需要运行以下命令:

REVOKE CREATE ON SCHEMA public FROM public;
Run Code Online (Sandbox Code Playgroud)

如果您REVOKE ALL(如其他答案所建议的那样),您还将阻止用户获得USAGE权限。USAGE意味着用户可以使用分配给他们的权限,因此如果您删除它,那么您的用户将无法列出或访问他们有权访问的表。

或者,您也可以REVOKE CREATE针对特定用户:

REVOKE CREATE ON schema public FROM myuser;
Run Code Online (Sandbox Code Playgroud)

另请参阅:如何使用 PostgreSQL 创建只读用户