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


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

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


而且没有任何其他授予,允许用户创建表:

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)


我希望用户在我对架构明确执行GRANT USAGE然后对表格进行GRANT SELECT之前不允许执行任何操作。

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

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

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

#1 楼

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

REVOKE ALL ON schema public FROM public;


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

GRANT ALL ON schema public TO foo_user;


要知道ALL对模式的含义,我们必须在文档(在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的任何架构中创建该对象的权限,就会发生这种情况。

评论


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

– andreas-h
13年2月23日在18:27

嗯现在数据库的所有者不再被允许创建表。参见上面的编辑。

– andreas-h
13年2月23日在18:48

@ andreas-h:编辑了更多详细信息的答案

–丹尼尔·韦里特(DanielVérité)
13年2月23日在19:33



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

– dezso
13年2月23日在19:41

@DanielVérité我已经在一个新的答案中阐述了其背后的概念,以补充您的答案。一个健全的检查将被重视。

–克雷格·林格(Craig Ringer)
2014年12月3日,2:12

#2 楼

这里要了解的关键是特权不是启发性的,也不是从包含对象继承的。 ALL表示此对象的所有特权,而不是此对象和所有包含的对象的所有特权。

在数据库上授予ALL时,就是在授予CREATE, CONNECT, TEMP。这些是对数据库对象本身的操作:



CONNECT:连接到DB

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也会成功。

与数据库和模式相同。

#3 楼

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

REVOKE CREATE ON SCHEMA public FROM public;


如果您REVOKE ALL(如其他答案所示),您还将防止用户具有USAGE权限。 USAGE意味着用户可以使用分配给他们的权限,因此,如果删除该权限,则用户将无法列出或访问他们可以访问的表。或者,您也可以使用REVOKE CREATE特定用户:

REVOKE CREATE ON schema public FROM myuser;


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