MySQL Userrechte

Etwas Verwirrung stiftere vor wenigen Tagen unser Datenbankadministrator mit seiner Behauptung, MySQL würde verändertes Recht erst dann lesen, wenn sich eine Anwendung mit der Datenbank verbindet. Diese Behauptung verblüffte mich doch ziemlich, da ich es eigentlich in Erinnerung hatte.

MySQL-Userverwaltung ist eine interessante Mischung aus dem Benutzer selbst und dem Host, von welchem er zugreift. Die Authentifizierung erfolgt also nicht nur über den Benutzer selbst und seinem Passwort, sondern auch eine Validierung des Urheberrechners findet statt.

Ein Benutzer banane@baum darf beispielsweise etwas, was aber einem banane@busch nicht erlaubt ist.

Dies ist aus sicherheitstechnischen Gründen durchaus eine sehr sinnvolle Einschränkung. Beispielsweise können damit Zugriffen aus einem internen Entwicklernetzwerk weitreichendere Zugriffsrechte eingeräumt werden, als beispielsweise der Fachabteilung, die ja bekannterweise von nichts Ahnung hat 😉

Wann und wie wirkt sich nun die Rechtevergabe aus?

Im wesentlichen können Rechte auf einem MySQL-Datenbanksystem auf zwei Arten vergeben werden:
– Durch direkte Befehl
– Durch einen Eintrag in die users Tabelle des mysql-Schemas
Befehle

GRANT – Befehl

Die erste Möglichkeit stellt die Durchführung von entsprechenden Befehlen. Dazu gehören: GRANT, REVOKE, SET PASSWORD, RENAME USER. Laut MySQL Handbuch

If you modify the grant tables indirectly using account-management statements such as GRANT, REVOKE, SET PASSWORD, or RENAME USER, the server notices these changes and loads the grant tables into memory again immediately.

Probieren wir das aus.

Als erstes legen wir eine leere Datenbank an:

 CREATE DATABASE banane;

Und probieren als Client (mit einem einfachen MySQL Client), ob wir erwartungsgemäß auch abgelehnt werden:

mysql -ubanane -pbanane
 ERROR 1045 (28000): Access denied for user 'banane'@'localhost' (using password: YES)

Wir vergeben als Administrator die entsprechende Rechte an den User:

GRANT ALL PRIVILEGES ON banane.* TO banane@localhost IDENTIFIED BY 'banane'

Unser Benutzer heißt banana mit dem entsprechenden Passwort. Da wir nur lokal auf den Testserver zurückgreifen, vergeben wir auch gleich nur den Localhost als zulässigen Host.

Test als Client:

mysql -ubanane -pbanane
 mysql>

Wunderbar, wir sind drin. Die Aussage aus dem Handbuch wird glorreich bestätigt: alle Rechte via GRANT wirken sofort.

Jetzt löschen wir das Recht wieder mit:

REVOKE ALL ON banane.* FROM banane@localhost;

Unsere Clientconnection bleibt bestehen, da die Rechte nur beim Login validiert warden. Also Abmelden und wieder Anmelden:

mysql - ubanane - pbanane
 mysql>

Hoppla! Ist da jetzt was schief gegagengen? Wir haben doch das Zugriffsrecht wieder entfernt? Warum kommt der Client dennoch rein?

Das hat mit dem MySQL-Sicherheitskonzept zu tun. Ein User per se darf zwar existieren, aber erst einmal gar nichts tun. Ihm müssen für jedes Tabellenschema Rechte gegeben werden, bevor er überhaupt etwas machen kann. Das probieren wir gleich mit:

Use banane;
 ERROR 1045 (28000): Access denied for user 'banane'@'localhost' (using password: YES)

Aha! Jetzt stimmt das. Wir können zwar auf das System zugreifen, aber eben nichts mehr tun, da der Zugriff auf das Schema banane wieder verboten wurde.

USERS

Für weitere Tests legen wir daher ein separates Tabellenschema ein:

CREATE DATABASE apfel;

Dieses Mal aber verwenden wir kein GRANT, sondern ergänzen die users-Tabelle:

INSERT INTO user (Host, User, Password, Select_priv) VALUES ('localhost', ‘apfel’, password('apfel1'), 'Y');

Der Verbindungsversuch:

mysql -uapfel -papfel1
 ERROR 1045 (28000): Access denied for user 'apfel'@'localhost' (using password: YES)

Obwohl der Datenbankeintrag vorhanden ist, wird unser Client tatsächlich abgelehnt. Das deckt sich wiederum mit dem MySQL-Handbuch:

If you modify the grant tables directly using statements such as INSERT, UPDATE, or DELETE, your changes have no effect on privilege checking until you either restart the server or tell it to reload the tables.

Nach dem Ausführen von

FLUSH_PRIVILEGES

gelingt der Verbindungsversuch:

mysql -uapfel -papfel1
 mysql>

Wir trennen die Verbindung und löschen den Eintrag aus der users-Tabelle:

DELETE FROM user where User=apfel;

Klappt jetzt der Verbindungsaufruf? Was meint Ihr? Natürlich, da eben kein FLUSH_PRIVILEGES durchgeführt wurde:

mysql -uapfel -papfel1
 mysql>

Wir führen als root den FLUSH_PRIVILEGES aus und verbinden uns als Client:

mysql -uapfel -papfel1
ERROR 1045 (28000): Access denied for user 'xentric1'@'localhost' (using password: YES)

Hoppla! Wir kommen dieses mal überhaupt nicht rein? Wieso das?

In diesem Falle löschten wir den gesamten User aus der Datenbank. Er ist einfach gar nicht mehr vorhanden. Im ersten Beispiel jedoch haben wir ihm nur die Rechte entzogen, der User blieb im System, daher das unterschiedliche Verhalten.

Man kann übrigens statt FLUSH_PRIVILEGES den Befehl mysqladmin reload durchführen, um dieselbe Wirkung zu erzielen.

Wir halten fest:

  1. Ein GRANT oder REVOKE wirken sich sofort, wobei REVOKE den User selbst nicht entfernt
  2. Eine Änderung in der users – Tabelle wirkt erst nach einem FLUSH_PRIVILEGES, reload oder einem Datenbankserverneustart

Wir haben es hier mit einer sehr häufigen und gefährlichen Situation zu tun: gerade in Developmentumgebungen wird gern mit breit gesetzten Rechten gearbeitet, die dann für einen Produktionsbetrieb eingeschränkt werden. Führt man diese Einschränkung aus, in dem nur die Tabelle users editiert wird, aber der FLUSH vergessen wird, sind die Rechte zwar scheinbar korrekt, de facto aber nicht und man arbeitet weiter mit wesentlich umfangreicheren Rechten, als gewünscht!

Eine Überprüfung der tatsächlich aktiven Privilegien liefert der Befehl SHOW GRANTS, der unbedingt auszuführen ist!

Leave a Reply

Your email address will not be published. Required fields are marked *