"Access permissions" - Warum kann der User sich einloggen?

Hallo,

Ich lege eine Datenbank an die “postgres” gehört, und einen User dem ich, außer das er sich einloggen darf, keine Rechte gebe. Warum darf der sich an der angelegten Datenbank anmelden, obwohl er nicht der Owner ist auch kein CONNECT Recht hat?

Ich versteh die Dokumentation so, dass dem User entweder die Datenbank “mydb” gehören müsste, oder er müsste das CONNECT Recht haben, sieht aber nicht so aus.

Vielleicht kann mir mit dieser Frage jemand helfen.

Danke,
Sven

In älteren Postgres Versionen (< 15) hat die Rolle “public” auch das Recht sich auf eine Datenbank zu verbinden. Wenn Du das verhindern willst, musst Du das Recht wegnehmen:

 revoke connect on database test from public;

oder eventuell

 revoke all on database test from public;
1 „Gefällt mir“

Kleine Korrektur: auch in Versionen nach 14 hat PUBLIC standardmäßig das CONNECT-Recht auf alle neuen Datenbanken. (Du hast das wahrscheinlich mit den Berechtigungen auf das Schema public durcheinandergebracht.)

Oops, ja habe ich.

Ich dachte irgendwie dabei wäre auch das connect Privileg dabei gewesen.

Ja, jetzt hab ich es auch gelesen:

PostgreSQL grants privileges on some types of objects to PUBLIC by default when the objects are created. No privileges are granted to PUBLIC by default on tables, table columns, sequences, foreign data wrappers, foreign servers, large objects, schemas, tablespaces, or configuration parameters. For other types of objects, the default privileges granted to PUBLIC are as follows: CONNECT and TEMPORARY (create temporary tables) privileges for databases; EXECUTE privilege for functions and procedures; and USAGE privilege for languages and data types (including domains).

Ich bin trotzdem etwas irritiert, weil man diese default Rechte nicht sehen kann.

Ich habe mal 2 Datenbanken, test1 und test2, gleichartig angelegt (Owner “postgres”). Direkt nach der Anlage sehe ich unter “Security” keinerlei “Privileges”.

Hier müssten jetzt also die default Rechte via der PUBLIC Rolle ziehen. Mein User “test”, der nicht Owner der beiden Datenbanken ist, kann sich zu beiden connecten, das passt also.

Wenn ich dann einer Datenbank ein Recht hinzufüge, werden plötzlich auch die Rechte von PUBLIC sichtbar:

postgres=# GRANT CONNECT ON DATABASE test1 to postgres ;
GRANT

Wenn ich jetzt die beiden Zeilen aus “Privilges” der Datenbank “test1” entferne, sehen beide Datenbanken gleich aus, beide zeigen keine “Access privileges”:

Name | Owner | Encoding | Locale Provider | Collate | Ctype | ICU Locale | ICU Rules | Access privileges
-----------±---------±---------±----------------±--------------------±--------------------±-----------±----------±----------------------
test1 | postgres | UTF8 | libc | German_Germany.1252 | German_Germany.1252 | | |
test2 | postgres | UTF8 | libc | German_Germany.1252 | German_Germany.1252 | | |

An der test1 kann sich mein User “test” jetzt aber nicht mehr connecten, an der test2 aber schon, obwohl sie scheinbar die gleichten Berechtigungen gesetzt haben:

➜ ~ psql -h localhost -U test test1
Password for user test:
psql: error: connection to server at “localhost” (127.0.0.1), port 5432 failed: FATAL: keine Berechtigung für Datenbank test1
DETAIL: Benutzer hat das CONNECT-Privileg nicht.
➜ ~ psql -h localhost -U test test2
Password for user test:
psql (16.0 (Debian 16.0-2))
Type “help” for help.

test2=>

Wo sehe ich denn jetzt wohl, dass die “test1” ihre magischen default Rechte via PUBLIC nicht mehr hat, die “test2” aber schon?

Sven

Ja, das ist eine blöde Sache. Die Rechte auf eine Tabelle sind in der Spalte pg_class.relacl gespeichert, und wenn da NULL drinnensteht, gelten die Defaultrechte. psql stellt das als Leerstring dar, was natürlich verwirrend ist, weil es genauso aussieht, wie wenn gar keine Rechte gesetzt wären.

In der Praxis hat man selten Problem damit, weil es nie Objekte gibt, auf die niemand Rechte hat. Auch wenn man PUBLIC alle Rechte auf eine Datenbank entzieht, sieht man noch immer die Rechte des Besitzers. Man müßte auch dem Besitzer alle Rechte entziehen, damit der Output in psql leer wird. Dann aber kann sich niemand an die Datenbank verbinden, und (wenn es kein Template ist) wäre das ziemlich sinnlos.

Es gab vor kurzem eine Diskussion darüber auf der Mailing List, aber ich finde sie jetzt nicht.

Das könnte man ja mit

\pset null '<null>'

ändern.

Ha! Ja, das ist es, super:

Habe wieder meine 2 Datenbanken test1 und test2 angelegt, der test1 habe ich manuell ein Recht gesetzt:

GRANT CONNECT ON database test1 to postgres;

Dann hab ich die beiden “Privileges” von test1 via pgadmin entfernt, und die beiden Datenbanken sehen sowohl im pgadmin, wie auch mit \l, erstmal gleich aus:

    Name         |        Owner        | Encoding |   Collate   |    Ctype    | ICU Locale | Locale Provider |    Access privileges

---------------------±--------------------±---------±------------±------------±-----------±----------------±------------------------
test1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc |
test2 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | | libc |

Jetzt sieht man aber in der pg_database den Unterschied. Einmal null, einmal leere Permissions, das erklärt es dann:

Danke für den Tipp, ich fand das verwirrend und freue mich es jetzt komplett verstanden zu haben.

Grüße,
Sven

Schön wär’s, aber geht nicht. psql zeigt in beiden Fällen einen Leerstring an, nicht NULL, also hat \pset null keinen Effekt.

Ich bevorzuge übrigens der Kürze wegen \pset null '∅'.

Das widerspricht aber Deiner Aussage:

Und bei mir funktioniert das auch:

Ok, ich muß das genauer erklären. Entschuldige für die Verwirrung stiftende Kürze.

  • In pg_class.relacl steht NULL, wenn eine Tabelle die Defaultrechte hat. Wenn man also direkt pg_class abfragt, sieht man den mit \pset null eingestellten String, und alles ist klar.
  • Einerlei, ob die Defaultrechte gelten (NULL in pg_class.relacl) oder ob tatsächlich alle Rechte entzogen wurden (leeres aclitem[] in pg_class.relacl), zeigt \dp <tabelle> einen Leerstring an. Also sieht man mit \dp nie, welche der beiden Fälle gilt, auch wenn man \pset null eingestellt hat.

Ich habe in meinem Kommentar den zweiten Punkt gemeint.

Klassisches Beispiel von “aneinander vorbeigeredet” :face_with_hand_over_mouth:

Es gibt übrigens im aktuellen Commitfest den Versuch, das zu verbessern. Zwei Patches sind in Diskussion:

  1. wenn gar keine Privilegien vorhanden sind, (none) hinschreiben

  2. NULLs in psql ganz normal darstellen, sodaß man die Fälle mit \pset null (null) unterscheiden kann

Wer Lust hat, auf Englisch seinen Senf dazuzugeben: bitte darum!