GUI vs. T-SQL – trotz dbo / db_owner keine Berechtigungen?

Wir haben heute für ein neues Projekt eines Kunden einen POC (Proof of Concept) durchgeführt und dabei unter anderem die angeforderten Berechtigungen des Herstellers überprüft. Unter anderem sollte das Servicekonto der Applikation in der Datenbank selbst Mitglied der Datenbankgruppe [db_owner] sein. Das haben wir aus Sicherheitsgründen abgelehnt. Unter anderem habe ich ausgeführt, dass Mitglieder der Gruppe [db_owner] durch Manipulation der Datenbankgröße mittelbaren Einfluss auf das Dateisystem haben. Dem widersprach der Hersteller und demonstrierte das Verhalten mit der GUI – das Ergebnis (auf einem SQL Server 2012war “verblüffend”.

Um das Verhalten nachzuvollziehen, wird zunächst ein Login ohne weitreichende Berechtigungen erstellt:

USE master;
GO

IF NOT EXISTS (SELECT * FROM sys.server_principals WHERE name = 'Test')
    CREATE LOGIN Test WITH PASSWORD = 'Abc$xxy', CHECK_POLICY = OFF, CHECK_EXPIRATION = OFF;
    GO

USE demodb;
GO

IF NOT EXISTS (SELECT * FROM sys.database_principals WHERE name = 'Test')
    CREATE USER Test FROM LOGIN Test;
    GO

EXEC sp_addrolemember @rolename = 'db_owner', @membername = 'Test';

Nachdem das Login erstellt wurde, wurde in der Datenbank [demodb] ein Benutzer angelegt. Dieser Benutzer wurde der festen Datenbankrolle [db_owner] zugewiesen. Diese spezielle Datenbankrolle hat besondere Berechtigungen in einer Datenbank. Mitglieder der festen Datenbankrolle [db_owner] können alle Aktivitäten zur Konfiguration und Wartung an der Datenbank ausführen.

Anschließend habe ich dem Mitarbeiter des Herstellers gezeigt, dass nun das Benutzerkonto die entsprechenden Berechtigungen für die Modifikation der Datenbankdateien hat. Dazu haben wir das folgende Skript ausgeführt:

USE dbdemo;
GO

EXECUTE AS Login = 'Test';

ALTER DATABASE dbdemo
MODIFY FILE
(
    name = demodata,
    SIZE = 200MB,
    MAXSIZE = 500MB
);

DBCC SHRINKFILE (demodata, 150);

REVERT

Unter dem Sicherheitskontext des Benutzers “Test” wurde in der Datenbank dbdemo zunächst die Datendatei auf 200 MB mit einer Begrenzung bis 500MB vergrößert. Im nächsten Schritt wurde die Datendatei wieder auf 150MB verkleinert. Die gleichen Aktionen sollten anschließend im Kontext des Benutzers “Test” mit Hilfe der GUI durchgeführt werden.

Zunächst wurde sich mit dem Server unter Verwendung des zuvor erstellten Logins verbunden. Das Vergrößern der Datendatei konnte (unter SQL Server 2012) ohne Probleme durchgeführt werden; ich war beruhigt, dass  mich meine Kenntnisse über das Sicherheitsmodell des Microsoft SQL Server nicht im Stich gelassen haben!

Im nächsten Schritt sollte der Mitarbeiter des Herstellers mittels GUI versuchen, die Datenbank-Dateien zu verkleinern:

Nachdem der Anwender auf den Befehl [Dateien…] geklickt hat, erschient statt des erwarteten Dialogs für die Konfiguration der Parameter folgender Dialog:

Die Fehlermeldung (297) ist untypisch für die durchzuführende Aktion, da Fehler 297 darauf hinweist, dass Berechtigungen für DMO (database management objects) nicht vorhanden sind. Um genau nachzuvollziehen, was im Hintergrund passiert, wenn der Benutzer den Dialog aufruft, haben wir einen Trace mit Hilfe des SQL Server Profilers während der Bedienung durch den Anwender durchführt.

Die obige Abbildung zeigt, welche Aktionen beim Öffnen des Dialogs durchgeführt werden. Die ersten drei Anweisungen wurden erfolgreich ausgeführt, während die vierte (und letzte) Anweisung scheinbar einen Fehler verursacht hat. Die komplette Abfrage wurde aus dem String – inklusive Parameter – herausgelöst und separat unter dem Konto des Benutzers “Test” ausgeführt:

SELECT CAST (
             
CASE s.type
                   WHEN 2 THEN s.size * CONVERT(float, 8)
                   ELSE dfs.allocated_extent_page_count * CONVERT(float, 8)
              END AS float
            )                        AS [UsedSpace],
            CASE s.type WHEN 2
                 THEN 0
                 ELSE 153600 - dfs.allocated_extent_page_count * CONVERT(float, 8)
            END                      AS [AvailableSpace]
FROM sys.filegroups AS g INNER JOIN sys.database_files AS s
     ON (
            (s.type = 2
OR s.type = 0) AND
            (s.drop_lsn IS NULL)
        )
AND
        (s.data_space_id = g.data_space_id) LEFT OUTER JOIN sys.dm_db_file_space_usage AS dfs
     ON dfs.database_id = db_id() AND
        dfs.file_id = s.file_id
WHERE
     s.name = 'dbdemo' AND
     g.data_space_id = 1;

Die obige Abfrage dient dazu, dem Benutzer im aufzurufenden Dialog die aktuelle Größe der Datei sowie die mögliche Verkleinerung anzuzeigen. Tests mit den einzelnen Objekten haben einen problemlosen Zugriff auf die Informationen ermöglicht; lediglich ein Zugriff auf sys.dm_db_file_space_usage wurde mit dem folgenden Fehler quittiert:

Meldung 297, Ebene 16, Status 1, Zeile 2
Der Benutzer hat nicht die Berechtigung, um diese Aktion auszuführen.

Genau diese Fehlermeldung wird durch den Dialog angezeigt und vermittelt dem Anwender, dass die aufgerufene Aktion nicht möglich ist. Das ist aber falsch. Der Fehler rührt lediglich daher, dass bei der Ermittlung der anzuzeigenden Daten ein Fehler aufgetreten ist – die eigentliche Aktion “DBCC SHRINKFILE” war – wie zuvor demonstriert - aus einem Abfragefenster ohne Probleme möglich.

Hier sind wohl die Entwickler von Microsoft in die typische Falle eines jeden Entwicklers getappt, der unter Berechtigungen eines sysadmin entwickelt und anschließend die Funktion nicht ausreichend mit “Standardbenutzern” getestet hat.

Fazit

Man sollte nicht immer den Fehlerdialogen trauen, die während der Arbeit mit Microsoft SQL Server auf Berechtigungsprobleme schließen lassen. Nicht immer zeigen die Dialoge das wahre Problem an sondern verschleiern – leider – die “Root Cause”.

Herzlichen Dank fürs Lesen!