Warum darf ein neuer Benutzer eine Tabelle erstellen?

41

Ich frage mich, warum ein neu erstellter Benutzer nach dem Herstellen einer Verbindung zu einer Datenbank eine Tabelle erstellen darf. Ich habe eine Datenbank 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)

So weit, ist es gut. Jetzt erstelle ich einen Benutzer:

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

Okay. Wenn ich versuche, eine Verbindung zur Datenbank herzustellen, darf der Benutzer dies nicht tun:

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

Das habe ich erwartet. Jetzt fängt das seltsame Zeug an. Ich erteile dem Benutzer 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)

Und ohne weitere Bewilligungen darf der Benutzer eine Tabelle erstellen:

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

Ich hätte erwartet, dass der Benutzer nichts tun darf, bevor ich explizit GRANT USAGEdas Schema und dann GRANT SELECTdie Tabellen bearbeitet habe.

Wo ist mein Fehler? Was mache ich falsch? Wie kann ich erreichen, was ich will (dass ein neuer Benutzer nichts tun darf, bevor er ihr explizit die entsprechenden Rechte gewährt?)?

Ich bin verloren und deine Hilfe wird sehr geschätzt :)

BEARBEITEN Nach dem Rat von @ daniel-verite widerrufe ich jetzt alle sofort nach dem Erstellen der Datenbank. Der Benutzer dietrich darf keine Tabelle mehr anlegen. Gut. ABER : Jetzt darf auch der Besitzer der Datenbank, project2 , keine Tabelle erstellen. Auch nach dem Ausstellen von GRANT ALL PRIVILEGES ON DATABASE project2_core TO project2und GRANT ALL PRIVILEGES ON SCHEMA public TO project2wird ein Fehler angezeigt. FEHLER: Es wurde kein Schema zum Erstellen ausgewählt. Wenn ich dies ausdrücklich versuche, CREATE TABLE public.WHATEVER ();wird die Berechtigung FEHLER: für das öffentliche Schema verweigert . Was mache ich falsch?

andreas-h
quelle

Antworten:

38

Wenn Sie eine neue Datenbank erstellen, kann jede Rolle Objekte im publicSchema erstellen . Um diese Möglichkeit zu entfernen, können Sie unmittelbar nach der Datenbankerstellung Folgendes ausführen:

REVOKE ALL ON schema public FROM public;

Bearbeiten: Nach dem obigen Befehl kann nur ein Superuser neue Objekte innerhalb des publicSchemas erstellen , was nicht praktikabel ist. Angenommen, einem Nicht-Superuser foo_usersollte dieses Privileg gewährt werden. Dies sollte erfolgen mit:

GRANT ALL ON schema public TO foo_user;

Um zu wissen, was ALLfür ein Schema bedeutet, müssen wir im Dokument auf GRANT verweisen (in PG 9.2 gibt es nicht weniger als 14 Formen von GRANT-Anweisungen, die für verschiedene Dinge gelten ...). Es scheint , dass für ein Schema bedeutet CREATEund USAGE.

Auf der anderen Seite, GRANT ALL PRIVILEGES ON DATABASE...gewähren CONNECTund CREATEund TEMP, aber CREATEin diesem Zusammenhang bezieht sich auf Schemata, nicht permanente Tabellen.

In Bezug auf diesen Fehler: tritt auf ERROR: no schema has been selected to create in, wenn versucht wird, ein Objekt ohne Schemaqualifizierung (wie in create table foo(...)) zu erstellen, während die Berechtigung zum Erstellen in einem beliebigen Schema des fehlt search_path.

Daniel Vérité
quelle
funktioniert :) Aber ich verstehe immer noch nicht: Ich habe es bereits versucht REVOKE ALL ON DATABASE project2_core FROM PUBLIC;. Warum hatte das keine Wirkung?
Andreas-h
mhh. Jetzt darf der Besitzer der Datenbank nicht CREATE TABLEmehr. siehe mein edit oben.
Andreas-h
@ andreas-h: bearbeitete die Antwort mit mehr Details
Daniel Vérité
Was den Fehler
betrifft
@ DanielVérité Ich habe die Konzepte dahinter in einer neuen Antwort erläutert, um Ihre zu ergänzen. Eine Plausibilitätsprüfung würde bewertet.
Craig Ringer
19

Das Entscheidende dabei ist, dass Privilegien nicht heirachisch sind und nicht von Objekten geerbt werden, die sie enthalten . ALLbedeutet alle Berechtigungen für dieses Objekt, nicht alle Berechtigungen für dieses Objekt und alle enthaltenen Objekte .

Wenn Sie ALLfür eine Datenbank gewähren, gewähren Sie CREATE, CONNECT, TEMP. Dies sind Aktionen für das Datenbankobjekt selbst:

  • CONNECT: Stellen Sie eine Verbindung zur DB her
  • CREATE: Erstellen Sie ein Schema ( keine Tabelle)
  • TEMP: Temporäre Objekte erstellen, einschließlich, aber nicht beschränkt auf temporäre Tabellen

Jetzt hat jede PostgreSQL-Datenbank standardmäßig ein publicSchema, das beim Erstellen der Datenbank erstellt wird. Diesem Schema sind alle Rechte für die Rolle publiczugewiesen, zu der implizit jeder gehört. Für ein Schema ALLbedeutet CREATE, USAGE:

  • CREATE: Erstellen Sie Objekte (einschließlich Tabellen) in diesem Schema
  • USAGE: Listet Objekte im Schema auf und greift auf sie zu, wenn ihre Berechtigungen dies zulassen

Wenn Sie nicht das Schema angeben, in dem ein Objekt wie eine Tabelle erstellt werden soll, verwendet das Datenbankmodul search_pathdas publicSchema. Standardmäßig befindet sich das Schema zuerst auf dem Schema, search_pathsodass die Tabelle dort erstellt wird. Jeder hat publicstandardmäßig Rechte , daher ist das Erstellen erlaubt. Die Rechte der Benutzer für die Datenbank sind zu diesem Zeitpunkt irrelevant, da der Benutzer nicht versucht, das Datenbankobjekt selbst zu bearbeiten, sondern nur ein darin enthaltenes Schema.

Es spielt keine Rolle, dass Sie dem Benutzer keine anderen Rechte als das Gewähren CONNECTfür die Datenbank gewährt haben , da das publicSchema standardmäßig allen Benutzern erlaubt, Tabellen darin zu erstellen. Daniel hat bereits erklärt, wie man dieses Recht auf Wunsch widerruft.

Wenn Sie jedes Recht explizit delegieren möchten, widerrufen Sie alle öffentlichen Rechte oder löschen Sie einfach das öffentliche Schema. Sie können eine neue Vorlagendatenbank mit dieser Änderung erstellen, wenn Sie möchten. Alternativ können Sie es anwenden template1, aber das wird wahrscheinlich eine Menge Code von Drittanbietern beschädigen, von dem angenommen wird, dass er publicexistiert und beschreibbar ist.


Dies ist möglicherweise sinnvoller, wenn Sie sich eine Dateisystem-Analogie ansehen.

Wenn ich die Verzeichnisstruktur habe (Modus vereinfacht, um nur den Modus anzuzeigen, der für den aktuellen Benutzer gilt):

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

dann kann ich innen nichts erstellen /dir1, da ich keine schreibberechtigung habe. Wenn ich also touch /dir1/somefileeinen Fehler erhalte, dem die Erlaubnis verweigert wurde.

Ich habe jedoch die Erlaubnis, nach innen zu schauen /dir1und auf enthaltene Dateien und Verzeichnisse zuzugreifen, einschließlich /dir1/dir2. Ich habe eine schriftliche Erlaubnis am dir2. So touch /dir1/dir2/somefilewird es gelingen , auch wenn ich keine Schreibberechtigung dazu habe dir1.

Gleiches gilt für Datenbanken und Schemata.

Craig Ringer
quelle
7

Wenn Sie nur verhindern möchten, dass neue Benutzer Tabellen erstellen, müssen Sie den folgenden Befehl ausführen:

REVOKE CREATE ON SCHEMA public FROM public;

Wenn Sie REVOKE ALL(wie aus anderen Antworten hervorgeht), verhindern Sie auch, dass Benutzer über USAGEBerechtigungen verfügen. USAGEbedeutet, dass Benutzer die ihnen zugewiesenen Berechtigungen verwenden können. Wenn Sie diese also entfernen, können Ihre Benutzer keine Tabellen auflisten oder auf Tabellen zugreifen, auf die sie Zugriff haben.

Alternativ könnten Sie auch REVOKE CREATEfür einen bestimmten Benutzer:

REVOKE CREATE ON schema public FROM myuser;

Siehe auch: So erstellen Sie einen schreibgeschützten Benutzer mit PostgreSQL .

Adrian Macneil
quelle