¿Por qué un nuevo usuario puede crear una tabla?


41

Me pregunto por qué un usuario recién creado puede crear una tabla después de conectarse a una base de datos. Tengo una base de datos 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)

Hasta aquí todo bien. Ahora creo un usuario:

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

Bueno. Cuando intento conectarme a la base de datos, el usuario no puede hacerlo:

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

Esto es lo que esperaba. Ahora comienzan las cosas extrañas. Le otorgo al usuario 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)

Y sin más concesiones, el usuario puede crear una tabla:

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

Hubiera esperado que el usuario no tenga permitido hacer nada antes de hacerlo explícitamente GRANT USAGEen el esquema y luego GRANT SELECTen las tablas.

¿Dónde está mi error? ¿Qué estoy haciendo mal? ¿Cómo puedo lograr lo que quiero (que un nuevo usuario no tenga permitido hacer nada antes de otorgarle explícitamente los derechos correspondientes)?

Estoy perdido, y tu ayuda es muy apreciada :)

EDITAR Siguiendo el consejo de @ daniel-verite, ahora revoqué todo inmediatamente después de crear la base de datos. El usuario dietrich ya no puede crear una tabla. Bueno. PERO : Ahora, también el propietario de la base de datos, project2 , no tiene permitido crear una tabla. Incluso después de emitir GRANT ALL PRIVILEGES ON DATABASE project2_core TO project2y GRANT ALL PRIVILEGES ON SCHEMA public TO project2recibo un error ERROR: no se ha seleccionado ningún esquema para crear , y cuando lo intento específicamente CREATE TABLE public.WHATEVER ();, obtengo ERROR: permiso denegado para el esquema público . ¿Qué estoy haciendo mal?

Respuestas:


38

Cuando crea una nueva base de datos, cualquier rol puede crear objetos en el publicesquema. Para eliminar esta posibilidad, puede emitir inmediatamente después de la creación de la base de datos:

REVOKE ALL ON schema public FROM public;

Editar: después del comando anterior, solo un superusuario puede crear nuevos objetos dentro del publicesquema, lo cual no es práctico. Asumiendo que a un no-superusuario foo_userse le debe otorgar este privilegio, esto se debe hacer con:

GRANT ALL ON schema public TO foo_user;

Para saber qué ALLsignifica para un esquema, debemos referirnos a GRANT en el documento , (en la PG 9.2 no hay menos de 14 formas de declaraciones GRANT que se aplican a diferentes cosas ...). Parece que para un esquema significa CREATEy USAGE.

Por otro lado, GRANT ALL PRIVILEGES ON DATABASE...otorgará CONNECTy CREATEy TEMP, pero CREATEen este contexto se relaciona con esquemas, no con tablas permanentes.

Con respecto a este error: ERROR: no schema has been selected to create inocurre cuando se intenta crear un objeto sin calificación de esquema (como en create table foo(...)) sin tener el permiso para crearlo en ningún esquema de search_path.


funciona :) Pero todavía no entiendo: ya lo intenté REVOKE ALL ON DATABASE project2_core FROM PUBLIC;. ¿Por qué esto no tuvo ningún efecto?
andreas-h

mhh ahora el propietario de la base de datos ya no está autorizado CREATE TABLE. mira mi edición arriba.
andreas-h

@ andreas-h: editó la respuesta con más detalles
Daniel Vérité

En cuanto al error, que puede ser fácilmente reproducido mediante la emisión de las órdenes de la pregunta y el revoque en orden :)
Dezso

@ DanielVérité He elaborado los conceptos detrás de esto en una nueva respuesta para complementar la suya. Se valoraría un control de cordura.
Craig Ringer

19

Lo crucial para entender aquí es que los privilegios no son heiraquicos y no se heredan de contener objetos . ALLsignifica todos los privilegios para este objeto, no todos los privilegios para este objeto y todos los objetos contenidos .

Cuando otorgas ALLen una base de datos, estás otorgando CREATE, CONNECT, TEMP. Estas son acciones en el objeto de la base de datos en sí mismo:

  • CONNECT: Conectarse a la base de datos
  • CREATE: Crear un esquema ( no una tabla)
  • TEMP: Crea objetos temporales, incluidas, entre otras, tablas temporales

Ahora, cada base de datos PostgreSQL por defecto tiene un publicesquema que se crea cuando se crea la base de datos. Este esquema tiene todos los derechos otorgados al rol public, del cual todos son implícitamente miembros. Para un esquema, ALLsignifica CREATE, USAGE:

  • CREATE: Crear objetos (incluidas tablas) dentro de este esquema
  • USAGE: Enumere los objetos en el esquema y acceda a ellos si sus permisos lo permiten

Si no especifica el esquema para crear un objeto como una tabla, el motor de la base de datos usa el search_path, y de manera predeterminada el publicesquema está primero en el, search_pathpor lo que la tabla se crea allí. Todos tienen derechos publicde forma predeterminada, por lo que se permite la creación. Los derechos de los usuarios en la base de datos son irrelevantes en este momento, ya que el usuario no está tratando de hacer nada al objeto de la base de datos, solo un esquema dentro de él.

No importa que no haya otorgado al usuario ningún derecho que no sea otorgar CONNECTen la base de datos, porque el publicesquema permite a todos los usuarios crear tablas en él de manera predeterminada. Daniel ya ha explicado cómo revocar ese derecho si lo desea.

Si desea delegar todos los derechos explícitamente, revoque todo de public, o simplemente descarte el esquema público. Puede crear una nueva base de datos de plantilla con este cambio aplicado si lo desea. Alternativamente, puede aplicarlo template1, pero eso probablemente romperá un montón de código de terceros que se supone que publicexiste y que se puede escribir.


Esto podría tener más sentido si observa una analogía del sistema de archivos.

Si tengo la estructura de directorios (modo simplificado para mostrar solo el modo que se aplica al usuario actual):

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

entonces no puedo crear nada dentro /dir1, porque no tengo permiso de escritura. Entonces, si touch /dir1/somefilerecibo un error de permiso denegado.

Sin embargo, tengo permiso para mirar dentro /dir1y acceder a archivos y directorios contenidos, incluidos/dir1/dir2 . Tengo permiso de escritura sobre dir2. Así touch /dir1/dir2/somefiletendrá éxito , a pesar de que no tengo permiso de escritura dir1.

Lo mismo con bases de datos y esquemas.


7

Si solo desea evitar que los nuevos usuarios creen tablas, debe ejecutar el siguiente comando:

REVOKE CREATE ON SCHEMA public FROM public;

Si tu REVOKE ALL (como sugieren otras respuestas), también evitará que los usuarios tengan USAGEpermisos. USAGEsignifica que los usuarios pueden usar los permisos asignados a ellos, por lo que si los elimina, sus usuarios no podrán enumerar o acceder a las tablas a las que tienen acceso.

Alternativamente, también podría REVOKE CREATEpara un usuario específico:

REVOKE CREATE ON schema public FROM myuser;

Consulte también: Cómo crear un usuario de solo lectura con PostgreSQL .

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.