"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!

Beide Patches werden in v17 kommen, also sollte die Situation ab dieser Version weniger verwirrend sein.

Ich habe das noch nicht alles nachvollzogen und gelesen, trotzdem erlaube ich mir ein paar Anmerkungen, wo es im Commitfest gerade um eine mögliche Änderung geht:

  1. Es geht um das “Default” Verhalten bei CreateDB.
  2. Um die Darstellung von NULL versus Leerstring.
  3. Um die Anzeige eines PSQL commands “\l”.

Richtig?

  1. Finde ich problematisch, zumindest die alten Versionen. Ein User der nicht am Create beteiligt ist, weder durch Durchführung, noch durch erhaltene Grants sollte eine DB vielleicht nicht mal sehen, außer er hat eine administrative Rolle, die das Wissen über „fremde“ DB erfordert (Backup, …). Dabei spielt es m.E. keine Rolle, ob es um SQL oder einen Befehl geht, es geht um sehr grundsätzliche Rechte- und Sicherheitsfragen.
  2. NULL ist verglichen mit Leerstring (oder grundsätzlich) ein problematischer Wert. Eine unterscheidbare Darstellung im Client scheint mir sehr sinnvoll, hat aber nicht direkt etwas mit dem Problem zu tun. Es ist keine sehr gute Argumentation, das Darstellungsproblem (3.) zu belassen.
  3. “\l” ist ein Befehl in psql. Ich gehe davon aus, dass ein View dahinter liegt, dessen Ergebnis dort angezeigt wird und der Impact, diese Anzeige “wasserdicht” zu machen, dürfte gegen Null gehen (vielleicht sogar NULL). :wink:

Wenn ich die Diskussion um Defaultrechte hier auf klassisches DB Verhalten umlege, so ist ein Default immer nur eine Definition (Ja, es geht hier wahrscheinlich nicht um einen Spaltendefaultwert). Sie sollte niemals eine Darstellung von Daten beeinflussen. Auch die gefühlte Häufigkeit des Problems sollte keinen Einfluss auf die Darstellung haben. Sonst sind wir ebenfalls “gefühlt” auf mySQL Niveau. (Ich weiß, es ist eine permanente Frage, welche Probleme man angeht, Kapazitäten, Prioritäten usw)

Die Anzeige von “\l” sollte m.E. den Prinzipien relationaler DB folgen, auch wenn es kein SQL ist, was man da aufruft (Es steckt hoffentlich jedoch eine SQL Abfrage dahinter). Es geht also nicht um das “Warum” irgendwas ist, sondern schlicht um die Anzeige von “Was” ist, diese Anzeige sollte zweifelsfrei sein und sehr wenig bis keinen Interpretationsspielraum lassen. Wenn wegen 2. die Darstellung problematisch ist und man sauber bleiben möchte, hilft ggf. eine abgeleitete Spalte, die das anzeigt. Bei Commands hat man ja im Gegensatz zu eigenen Statements direkt keine Möglichkeit, die Darstellung nachzuvollziehen.
(Ich gehe davon aus, dass man mit der Abfrage diverser Repository Tables/Views allerdings genau das tun könnte.)

Und noch was ganz anderes dazu, wilde Idee:
Seit einiger Zeit gibt es diese schönen Typo Fehlermeldungen bei fehlerhaften SQL Statements, die auf Spaltennamen mit ähnlicher Schreibweise hindeuten. Das ist Lichtjahre weiter als andere DB oder neutraler formuliert, eines der Merkmale für die Qualität der PG Fehlermeldungen. Kann man solche Mechanismen in Problemfällen nicht an anderer Stelle auch etablieren? Gerade ein Command (ohne Fehlermeldung) wäre dafür vielleicht ein Aufhänger / Rahmen. Ich sag jetzt einfach mal ein “explain” zu commands.
Die Diskussion hier und in den Maillisten zeigt ja, dass sich bereits viele mit dem Problem beschäftigt haben. Es gibt also ein immanentes Wissen dazu. Warum sollte man da drum herum “programmieren” ohne Transparenz zu liefern?

Teilweise. Es geht um “Metakommandos” wie \l, obwohl das problematische Kommando \z oder \dp ist (Permissions auf einer Tabelle). Und ja, NULL soll nicht mehr zwingend als Leerstring dargestellt werden, sondern so, wie sonst auch überall anders so dargestellt werden, wie man es mit \pset null eingestellt hat.

Das Problem ist, daß “keine Rechte” (eine leere ACL) genauso dargestellt wird with “Defaultrechte” (NULL im Systemkatalog), was verwirrend ist.

Die Änderung ist bereits committed, also wird sich das Verhalten in v17 ändern:

  1. “keine Rechte” wird als (none) dargestellt
  2. Wenn man mit \pset null '∅' die NULL-Darstellung ändert, betrifft das auch die Defaultrechte.

Das ist ein ganz anderes Thema, und dieser Zug ist längst abgefahren. Jeder kann in PostgreSQL fast alle Metadaten sehen. Wir mögen das so. Wem das nicht gefällt, der kann sich ja mit CREATE DATABASE eine eigene Datenbank anlegen.

Gut! Das ist genau die Änderung, die in v17 passiert ist.

Das verstehe ich nicht ganz. Wenn man direkt den Katalog abfragt, sieht man die NULLs.

Das ist ein völlig anderes Thema und gehört hier nicht dazu.

Danke für Deine Erläuterungen.

Ja, das meinte ich mit

Das mag ich auch. Es macht auch sehr viel Sinn. Als Einschränkung würde ich lediglich sehen, dass abhängig von den Nutzerrechten, auch der Zugriff auf Dictionarydaten eingeschränkt sein kann oder sogar sollte.

Eben, wir reden einerseits von “Metakommandos”, die ich als Anwender “hinnehmen” muss und deren Aufbau ich nicht ohne Weiteres einsehen und damit “verstehen” kann. Andererseits von reinem SQL, was ich nach eigenem Belieben formulieren kann und damit die Werte Ausgabe nach eigenem Ermessen und Vorlieben beliebig beeinflussen kann. Diese zweite Perspektive ist eine Möglichkeit für Anwender auszulesen, was immer sie möchten/können, allerdings keine Option für das Metakommand in diesem Thread.

Naja, technisch gesehen ist eine Idee zu einer erweiterten Hilfe sicher keine Antwort auf das Problem selbst. Es ist einfach eine Anregung. Egal, vergessen wir’s.

Du kannst gerne einen Vorschlag auf der pgsql-hackers Liste machen. Ich glaube, du wirst einen schweren Stand haben, weil Kompatibilität mit früheren Versionen für PostgreSQL sehr wichtig ist. Aber was hat das mit diesem Thread zu tun?

Damit wollte ich nicht sagen, daß die Idee irgendwie schlecht ist (ich habe sie nicht näher betrachtet). Ich halte es nur für eine gute Sache, die Diskussion beim ursprünglichen Thema zu lassen. Warum beginnst du nicht eine neue Diskussion?

Dieses Thema wurde automatisch 60 Tage nach der letzten Antwort geschlossen. Es sind keine neuen Antworten mehr erlaubt.