Por que um novo usuário pode criar uma tabela?

41

Eu estou querendo saber por que um usuário recém-criado tem permissão para criar uma tabela depois de se conectar a um banco de dados. Eu tenho um banco de dados 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)

Por enquanto, tudo bem. Agora eu crio um usuário:

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

OK. Quando tento me conectar ao banco de dados, o usuário não tem permissão para fazer isso:

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

Isto é o que eu esperava. Agora as coisas estranhas começam. Eu concedo ao usuário 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)

E sem outras concessões, o usuário pode criar uma tabela:

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

Eu esperava que o usuário não tivesse permissão para fazer nada antes de eu explicitamente fazer GRANT USAGEo esquema e depois GRANT SELECTas tabelas.

Onde está meu erro? O que estou fazendo errado? Como posso conseguir o que quero (que um novo usuário não tenha permissão para fazer nada antes de conceder explicitamente a ela os direitos apropriados.

Estou perdido, e sua ajuda é muito apreciada :)

EDIT Seguindo o conselho de @ daniel-verite, agora revoco tudo imediatamente após a criação do banco de dados. O usuário dietrich não pode mais criar uma tabela. Boa. MAS : Agora, também o proprietário do banco de dados, projeto2 , não tem permissão para criar uma tabela. Mesmo após a emissão GRANT ALL PRIVILEGES ON DATABASE project2_core TO project2e GRANT ALL PRIVILEGES ON SCHEMA public TO project2, recebo um erro ERRO: nenhum esquema foi selecionado para criação e, quando tento especificamente CREATE TABLE public.WHATEVER ();, recebo a permissão ERRO: negada para o público do esquema . O que estou fazendo errado?

andreas-h
fonte

Respostas:

38

Quando você cria um novo banco de dados, qualquer função tem permissão para criar objetos no publicesquema. Para remover essa possibilidade, você pode emitir imediatamente após a criação do banco de dados:

REVOKE ALL ON schema public FROM public;

Edit: após o comando acima, apenas um superusuário pode criar novos objetos dentro do publicesquema, o que não é prático. Supondo que um não-superusuário foo_userdeva receber esse privilégio, isso deve ser feito com:

GRANT ALL ON schema public TO foo_user;

Para saber o que ALLsignifica um esquema, devemos nos referir a GRANT no documento (na PG 9.2, há pelo menos 14 formas de instruções GRANT que se aplicam a coisas diferentes ...). Parece que para um esquema significa CREATEe USAGE.

Por outro lado, GRANT ALL PRIVILEGES ON DATABASE...irá conceder CONNECTe CREATEe TEMP, mas CREATEneste contexto diz respeito a esquemas, não tabelas permanentes.

Com relação a este erro ERROR: no schema has been selected to create in:, isso ocorre ao tentar criar um objeto sem qualificação de esquema (como em create table foo(...)), enquanto falta a permissão para criá-lo em qualquer esquema do search_path.

Daniel Vérité
fonte
funciona :) Mas ainda não entendi: já tentei REVOKE ALL ON DATABASE project2_core FROM PUBLIC;. por que isso não teve nenhum efeito?
andreas-h
mhh. agora o proprietário do banco de dados não tem mais permissão CREATE TABLE. veja minha edição acima.
andreas-h
@ andreas-h: editado a resposta com mais detalhes
Daniel Vérité
Quanto ao erro, ele pode ser facilmente reproduzido emitindo os comandos a partir da pergunta e seu REVOKE, a fim :)
Dezso
@ DanielVérité Eu elaborei os conceitos por trás disso em uma nova resposta para complementar a sua. Uma verificação de sanidade seria avaliada.
Craig Ringer
19

O ponto crucial a entender aqui é que os privilégios não são heiráquicos e não são herdados de objetos contidos . ALLsignifica todos os privilégios para esse objeto nem todos os privilégios para esse objeto e todos os objetos contidos .

Quando você concede ALLem um banco de dados, está concedendo CREATE, CONNECT, TEMP. Estas são ações no objeto de banco de dados:

  • CONNECT: Conecte-se ao banco de dados
  • CREATE: Criar um esquema ( não uma tabela)
  • TEMP: Criar objetos temporários, incluindo, entre outros, tabelas temporárias

Agora, cada banco de dados PostgreSQL, por padrão, possui um publicesquema criado quando o banco de dados é criado. Esse esquema tem todos os direitos concedidos à função public, dos quais todos são implicitamente membros. Para um esquema, ALLsignifica CREATE, USAGE:

  • CREATE: Criar objetos (incluindo tabelas) dentro deste esquema
  • USAGE: Lista objetos no esquema e acesse-os se suas permissões permitirem

Se você não especificar o esquema para criar um objeto como uma tabela, o mecanismo de banco de dados utilizará o search_pathe, por padrão, o publicesquema será o primeiro search_patha ser criado para a tabela. Como todos têm direitos publicpor padrão, a criação é permitida. Os direitos dos usuários no banco de dados são irrelevantes neste momento, pois o usuário não está tentando fazer nada com o objeto de banco de dados, apenas um esquema dentro dele.

Não importa que você não tenha concedido ao usuário outros direitos além da concessão CONNECTno banco de dados, porque o publicesquema permite que todos os usuários criem tabelas nele por padrão. Daniel já explicou como revogar esse direito, se desejado.

Se você deseja delegar todos os direitos explicitamente, revogue tudo de public, ou simplesmente elimine o esquema público. Você pode criar um novo banco de dados de modelos com essa alteração aplicada, se desejar. Como alternativa, você pode aplicá-lo template1, mas isso provavelmente quebrará muitos códigos de terceiros que supõem que publicexista e sejam graváveis.


Isso pode fazer mais sentido se você olhar para uma analogia do sistema de arquivos.

Se eu tiver a estrutura de diretórios (modo simplificado para mostrar apenas o modo que se aplica ao usuário atual):

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

então não posso criar nada dentro /dir1, porque não tenho permissão de gravação. Portanto, se eu touch /dir1/somefilereceber um erro de permissão negada.

No entanto, eu faço tem permissão para olhar para dentro /dir1e para acesso continha arquivos e diretórios, inclusive /dir1/dir2. Eu tenho permissão de gravação dir2. Então, touch /dir1/dir2/somefileterá sucesso , mesmo que eu não tenha permissão de gravação dir1.

A mesma coisa com bancos de dados e esquemas.

Craig Ringer
fonte
7

Se você deseja impedir apenas que novos usuários criem tabelas, execute o seguinte comando:

REVOKE CREATE ON SCHEMA public FROM public;

Se você REVOKE ALL(como outras respostas sugerem), também impedirá que os usuários tenham USAGEpermissões. USAGEsignifica que os usuários podem usar as permissões atribuídas a eles; portanto, se você remover isso, seus usuários não poderão listar ou acessar as tabelas às quais têm acesso.

Como alternativa, você também pode REVOKE CREATEpara um usuário específico:

REVOKE CREATE ON schema public FROM myuser;

Veja também: Como criar um usuário somente leitura com o PostgreSQL .

Adrian Macneil
fonte