Oracle Virtual Private Database
von Heinz-Wilhelm Fabry, ORACLE Deutschland GmbH
Die existierenden Objektprivilegien, die Anwendern das Lesen, Einfügen,
Ändern und Löschen von Daten erlauben, zielen immer auf alle Zeilen einer Tabelle. Soll
der Zugriff auf Zeilenebene gesteuert werden, weicht man entweder auf die Steuerung des
Zugriffs über Anwendungen aus oder verwendet Views. Beides ist uneffektiv: Die Steuerung
über Anwendungen, weil sie in jeder Anwendung separat programmiert werden muss und
Änderungen in jeder Anwendung nachgezogen werden müssen. Die Steuerung über Views, weil bei
großen Benutzergruppen oder vielen Views das ganze Berechtigungssystem schnell
unüberschaubar wird.
Oracle bietet schon seit der Version Oracle8i eine Lösung für dieses Problem:
Die Lösung ist unter den Namen Fine Grained Access Control (FGAC) oder auch Virtual Private
Database (VPD) bekannt. Es handelt sich dabei um ein Feature der Enterprise
Edition, dessen Nutzung in der Regel eine enge Zusammenarbeit von Datenbankadministratoren
und Anwendungsentwicklern voraussetzt.
VPD implementiert die Kontrolle für den Zugriff auf einzelne Zeilen auf der Ebene
der Tabelle: Mit dem Paket DBMS_RLS werden die Befehle INSERT, UPDATE, DELETE und SELECT,
die auf eine mit VPD geschützte Tabelle zugreifen, um eine zusätzliche WHERE-Bedingung
erweitert. Diese WHERE-Bedingung wird flexibel durch eine Funktion erstellt, die der
Datenbankadministrator oder Anwendungsentwickler schreiben muß. Enthält das SELECT, UPDATE
oder DELETE bereits eine WHERE-Bedingung, wird die von der Funktion erzeugte WHERE-Bedingung
einfach mit AND angehängt. Die Verbindung zwischen Funktion und Tabelle wird als Policy
bezeichnet, und die Funktion deshalb auch als Policy-Funktion.
Es ist möglich, identische oder auch unterschiedliche Policy-Funktionen für die Aktionen SELECT,
INSERT, UPDATE und DELETE anzulegen. Sogar mehrere Policy-Funktionen für ein und dieselbe Aktion
sind erlaubt. Und man kann auch Policy-Funktionen in Gruppen zusammenlegen (Oracle-Terminologie
PARTITIONED FGAC): Die Ergebnisse der Funktionen werden einfach durch AND verbunden.
Die wahre Leistungsfähigkeit der VPD offenbart sich aber erst im Zusammenspiel mit Variablen,
die als sogenannter Application Context im Arbeitsspeicher angelegt werden. Ein Application
Context kann z. B. beim ersten Connect auf die Datenbank im Rahmen eines Logon-Triggers mit
Werten aus der Betriebssystem- oder Anwendungsumgebung des Anwenders aber auch mit Informationen
aus der Datenbank initialisiert werden. Durch den Zugriff auf den Application Context vermeiden
Policy-Funktionen dann unnötige Mehrfachausführungen von Programmcode oder aufwendige SQL-Zugriffe.
Ein Application Context kann im Bereich des Arbeitsspeichers eines Anwenders
angelegt werden. Er kann aber auch in einem Bereich angelegt werden, der für alle Benutzer verfügbar ist.
Dann spricht man von sogenannten Global Application Contexts. Global Application Contexts
unterstützen das Connection Pooling, Multitier-Anwendungen oder Anwendungen, die ihre eigene
Authentifizierung vornehmen und selbst als Datenbankbenutzer agieren.
Anhand eines Beispiels soll die Verwendung von Policies und Application Contexts im Rahmen von VPD
vorgestellt werden. Das Beispiel basiert auf den Tabellen EMPLOYEES, ORDERS und CUSTOMERS aus
den Beispielschemas HR und OE. Beide Schemas sind im Lieferumfang der Datenbank enthalten und in der
folgenden Graphik ausschnittweise dargestellt.
Zum Vergrößern auf das Bild klicken, zurück zum Artikel mit dem Back-Button des Browser
Für das Beispiel werden die Tabellen modifiziert. Um eindeutige Nummernkreise
für Angestellten- und Kundennummern (employee_id, customer_id) zu erhalten, werden die
Kundennummern in ORDERS und CUSTOMERS mit 10
multipliziert. Dazu wird das Foreign Key Constraint auf ORDERS.CUSTOMER_ID zuvor mit DROP gelöscht.
Ausserdem wird der Zugriff auf die Tabelle ORDERS für Verkäufer und Kunden freigegeben.
Aufgabenstellung
Die Auftragsdaten aus ORDERS sollen nur von den Verkäufern, die den Auftrag abgeschlossen
haben, lesbar sein. Ausserdem sollen Kunden ihre eigenen Auftragsdaten lesen dürfen.
Der Lösungsweg sieht so aus, dass im Rahmen eines Logon-Triggers Variablen eines Application Context
gefüllt werden, die dann im zweiten Schritt für die Policies gebraucht werden. Dabei wird davon
ausgegangen, dass die Verkäufer sich mit ihrem Emailnamen einloggen. Dieser Emailname
wird in der Tabelle EMPLOYEES in der Spalte EMAIL gelistet und besteht aus dem 1. Buchstaben des
Vornamens und dem vollständigen Nachnamen. Analog sind die Kundenzugänge über Benutzernamen möglich,
die ebenfalls nach diesem Muster aufgebaut sind.
Application Contexts und Logon-Trigger anlegen
Da das Anlegen der folgenden Objekte mehr als die üblichen Benutzerprivilegien erfordert, sollen
die Objekte des Beispiels der Einfachheit halber von einem DBA angelegt werden, hier vom Benutzer
SYSTEM.
Der Application Context wird mit folgendem Befehl angelegt
initpack ist der Name eines Package, das zum Erstellen und Füllen der Variablen des
Application Context genutzt wird. Das Package wird folgendermassen erstellt.
Zur Erläuterung: Nach der Deklaration der Variablen V_BENUTZER_ID wird in der Prozedur zunächst
die Angestelltennummer
(employee_id) des Verkäufers gesucht. Dies geschieht mit der im Lieferumfang der
Datenbank enthaltenen Funktion SYS_CONTEXT. Liefert das SELECT ein Ergebnis, wird dieses Ergebnis
durch den Aufruf von DBMS_SESSION.SET_CONTEXT dem
Application Context INITVPD in der Variablen BENUTZER_ID zur Verfügung gestellt. Scheitert das SELECT,
handelt es sich offenbar nicht um einen Verkäufer, sondern um einen Kunden. Dessen
Kundennummer wird im EXCEPTION HANDLER ermittelt und der Variablen BENUTZER_ID des Context INITVPD
zugewiesen. Das bedeutet, dass diese Variable immer einen Wert hat, sofern ein Verkäufer
oder ein Kunde diese Prozedur zur Ausführung bringt.
Die Prozedur initpack.benutzerdaten soll durch einen Logon-Trigger ausgeführt werden, der mit
folgendem Befehl erstellt wird.
Policy-Funktion anlegen
Folgende Policy-Funktion führt zur Umsetzung der genannten Anforderungen.
Zur Erläuterung: Nach der Deklaration der Variablen liest das SELECT über die Funktion SYS_CONTEXT
die Variable BENUTZER_ID aus dem Application Context INITVPD in die lokale Variable V_BENUTZER_ID.
Der Variablen BEDINGUNG wird ein Wert in Form einer Zeichenkette zugewiesen, in die wiederum die
Variable V_BENUTZER_ID eingebaut wird. Die so entstandene Zeichenkette kann als als WHERE-Bedingung
durch die VPD genutzt werden.
Die Funktion wird mit den Rechten des Eigentümers ausgeführt. Ihr stehen nicht nur die Möglichkeiten
von PL/SQL zur Verfügung, sondern es ist auch möglich, C- oder Java-Programme einzubinden. Da der Code
der Policy-Funktion zusätzlich ausgeführt werden muss, ist es sinnvoll, diesen Code so kompakt wie möglich
zu gestalten.
Die Struktur der Funktion ist in zwei Punkten vorgegeben: Sie muss erstens zwei Eingabeparameter
zur Verfügung stellen.
Das System benötigt diese Informationen , um die Tabelle zu identifizieren, auf die die
Funktion angewendet werden soll. Gleichzeitig hält die Parametrisierung die Möglichkeit offen, die
Funktion auf unterschiedliche Tabellen anzuwenden. Die Parameter sind im Beispiel mit den sprechenden
Namen SCHEMANAME und TABNAME angelegt. Zweitens muss die Funktion als Rückgabewert eine
Zeichenkette liefern. In unserem Beispiel ist die Variable BEDINGUNG wie beschrieben für diese
Zeichenkette vorgesehen.
Zwei Hinweise für die Praktiker:
1. Läßt sich die Funktion kompilieren und treten erst zur
Laufzeit Probleme auf, erhält man durch einen Blick in die Trace-Datei (unter USER_DUMP_DEST)
hilfreiche Informationen zur Fehleranalyse.
2. Bitte in der Funktion nicht auf die Tabelle zugreifen, für die die Funktion ausgeführt werden soll. Es
treten sonst Fehler auf, die vergleichbar sind mit denen, die bei Triggern als mutating table bekannt sind.
Die Verbindung der Funktion mit einer Tabelle erfolgt über das Paket DBMS_RLS. SYSTEM hat Zugriff
auf dieses Paket.
Die Parameter OBJECT_SCHEMA, OBJECT_NAME und POLICY_FUNCTION legen fest, für welches Objekt die Policy
gilt. Der Parameter POLICY_NAME gibt dieser Verbindung von Funktion und Tabelle einen Namen, hier
O_POLICY. Unter diesem Namen kann die Policy in anderen Zusammenhängen, z. B. um sie zu löschen,
angesprochen werden. Der Parameter STATEMENT_TYPES legt fest, dass die Funktion nur für den Befehl
SELECT ausgeführt wird.
Das Ergebnis
Der folgende Screenshot zeigt, dass das identische Statement einmal ausgeführt von dem Verkäufer
COLSEN und einmal ausgeführt durch den Kunden EFAWCETT unterschiedliche Ergebnisse liefern. Die
VPD funktioniert. Trotz der scheinbar gleichen Abfrage wird die Ergebnismenge durch die
unterschiedlichen WHERE-Bedingungen jeweils unterschiedlich: Jeder sieht nur die für ihn durch
die WHERE-Bedingung gefilterten Datensätze.
Zum Vergrößern auf das Bild klicken, zurück zum Artikel mit dem Back-Button des Browser
Weitere Hinweise
Das Beispiel zeigt nur eine Verwendungsmöglichkeit von VPD. Eine andere, die ebenso leicht
aufzusetzen ist, könnte z.B. das Lesen aller Zeilen einer Tabelle grundsätzlich erlauben - außer
wenn schützenswerte Spalten angesprochen werden. Hier entscheidet dann die unternehmensspezifische
Praxis, ob durch den Zugriff auf eine schützenswerte Spalte der gesamte selektierte Satz nicht angezeigt
wird, oder ob die Werte der geschützten Spalte als NULL dargestellt werden.
Die VPD-Infrastruktur ist für die Anwender nicht sichtbar - in der Oracle-Terminologie transparent.
Die Policies werden auf alle Benutzer außer auf den Benutzer SYS angewendet: SYS hat als einziger das
Privileg EXEMPT ACCESS POLICY. Allerdings kann sich ein 'normaler' Datenbankadministrator das Privileg
zuweisen. Soll auf jeden Fall verhindert werden, dass Datenbankadministratoren auf Benutzerdaten
zugreifen, geschieht das durch den Einsatz der Datenbankoption Oracle Database Vault.
Die VPD-Technologie wird eingesetzt für Anwendungen, in denen innerhalb eines Unternehmens mit
unterschiedlichen Privilegien auf unterschiedliche Tabellenzeilen zugegriffen wird, bis hin zur
Implementierung von mandantenfähigen Tabellen durch Outsourcing-Dienstleister, das heißt, dass Daten
vieler Kunden in einer einzigen Tabelle gespeichert und damit das Anlegen separater Tabellen oder gar
ganzer Datenbanken pro Kunde vermieden wird.
Weitere Informationen zum Thema VPD finden sich im Security Guide, im
Oracle Technology Network oder in Form eines weiteren Beispiels auch auf den Seiten der Application Express Community.
Zurück zur Community-Seite
|