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


41

我想知道为什么允许新创建的用户连接到数据库后创建表。我有一个数据库,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)

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

postgres=# CREATE ROLE dietrich ENCRYPTED PASSWORD 'md5XXX' LOGIN NOCREATEROLE NOCREATEDB NOSUPERUSER

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

$ 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.

这是我所期望的。现在奇怪的东西开始了。我授予用户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)

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

$ 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)

我曾希望在我GRANT USAGE对模式然后GRANT SELECT对表进行显式操作之前,不允许用户执行任何操作。

我的错误在哪里?我究竟做错了什么?我如何实现自己想要的(新用户在明确授予她适当的权限之前,不允许执行任何操作。

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

编辑按照@ daniel-verite的建议,我现在在创建数据库后立即撤销所有操作。用户DietDirich不再可以创建表。好。但是:现在,数据库的所有者project2也不允许创建表。甚至在发出GRANT ALL PRIVILEGES ON DATABASE project2_core TO project2and之后GRANT ALL PRIVILEGES ON SCHEMA public TO project2,我仍然收到错误ERROR:未选择要在其中创建的架构,而当我专门尝试这样做时CREATE TABLE public.WHATEVER ();,我得到了ERROR:架构public的权限被拒绝。我究竟做错了什么?

Answers:


38

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

REVOKE ALL ON schema public FROM public;

编辑:在上述命令之后,只有超级用户可以在public架构内创建新对象,这是不实际的。假设foo_user应授予非超级用户此特权,请使用以下方法完成此操作:

GRANT ALL ON schema public TO foo_user;

要知道ALL对架构意味着什么,我们必须在doc中引用GRANT(在PG 9.2中,有不少于14种形式的GRANT语句适用于不同的事物...)。看来,对于一个模式,它意味着CREATEUSAGE

另一方面,GRANT ALL PRIVILEGES ON DATABASE...will grant CONNECTCREATETEMP,但CREATE在这种情况下与模式有关,而不与永久表有关。

关于此错误:ERROR: no schema has been selected to create in,当尝试创建没有架构限定条件的对象(如中create table foo(...))而又没有在的任何架构中创建对象的权限时,就会发生这种错误search_path


的作品:)但是我还是不明白:我已经尝试过了REVOKE ALL ON DATABASE project2_core FROM PUBLIC;。为什么这没有效果?
andreas-h

嗯 现在,该数据库的所有者不再被允许CREATE TABLE。参见上面的编辑。
andreas-h

@ andreas-h:更详细地编辑了答案
DanielVérité13年

关于错误,可以通过按顺序发出问题中的命令和您的REVOKE来轻松重现它:)
dezso 2013年

@DanielVérité我已经在一个新的答案中阐述了其背后的概念,以补充您的答案。进行健全检查。
Craig Ringer 2014年

19

在这里要理解的关键是特权不是具有启发性的也不是从包含对象继承的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)已经说明了如何根据需要撤销该权利。

如果要显式委派每个权限,请从公共撤消所有权限,或直接删除公共架构。您可以根据需要应用此更改来创建新的模板数据库。另外,您也可以将其应用于template1,但这可能会破坏很多假定public存在并且可写的第三方代码。


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

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

/dir1           mode=r-x
/dir1/dir2      mode=rwx

则我无法在中创建任何内容/dir1,因为我没有写权限。因此,如果我touch /dir1/somefile将收到一个权限被拒绝的错误。

但是,我确实有权查看内部/dir1并访问包含的文件和目录,包括/dir1/dir2。我有的写许可dir2。即使我没有书面许可,这样touch /dir1/dir2/somefile也会成功dir1

数据库和架构也是如此。


7

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

REVOKE CREATE ON SCHEMA public FROM public;

如果您REVOKE ALL(如其他答案所建议),您还将阻止用户拥有USAGE权限。USAGE表示用户可以使用分配给他们的权限,因此,如果删除该权限,则用户将无法列出或访问他们有权访问的表。

另外,您也可以REVOKE CREATE针对特定用户:

REVOKE CREATE ON schema public FROM myuser;

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.