Betrifft: "Invoker Rights" mit DBMS_SYS_SQL..PARSE_AS_USER

Art der Info: PL/SQL-Tipps und Tricks aus der Praxis

Autor: Guido Schmutz (guido.schmutz@trivadis.com)

Quelle: Aus der Trivadis Schulung

 

Einleitung

Bis und mit Version 8.0 kannte Oracle nur das Definer Rights Sicherheitsmodell. Mit diesem Modell läuft ein PL/SQL Programm unter den Rechten des Besitzers ab. Dies ist oft gewünscht und bringt die gewünschten Resultate. Gerade bei der Verwendung von dynamischem SQL ist dieses Verhalten aber oft problematisch, was an folgendem Beispiel gezeigt werden soll.

 

Es soll eine Prozedur geschrieben werden, über die der Benutzer sein Passwort ändern kann. Da man aus PL/SQL nur DML und Queries direkt absetzen kann, der benötigte ALTER USER Befehl aber zur Kategorie der DDL Befehle gehört, muss für diese Anforderung dynamisches SQL eingesetzt werden. Hier die entsprechende Implementation der Prozedur mittels DBMS_SQL:

 

CONNECT stpw/stpw@db1

CREATE OR REPLACE

PROCEDURE chg_password (in_password IN VARCHAR2)

IS

  cur INTEGER;

BEGIN

  cur := DBMS_SQL.open_cursor;

  DBMS_SQL.parse (cur

      , 'ALTER USER ' || USER || ' IDENTIFIED BY ' || in_password

            , DBMS_SQL.native);

  DBMS_SQL.close_cursor (cur);

END chg_password;

/

 

 

Ein kleiner Test zeigt, dass das Ganze lokal problemlos funktioniert:

 

SQLWKS> BEGIN

     2>       chg_password ('test');

     3> END;

     4>

Statement processed.

SQLWKS> CONNECT stpw/test@db1

Connected.

 

 

Wenn man nun aber die Prozedur einem anderen Benutzer (SCOTT) zur Verfügung stellen möchte, ergibt sich bei der Verwendung folgendes Problem:

 

GRANT EXECUTE ON chg_password TO scott;

 

CONNECT scott/tiger@db1

SQLWKS> BEGIN

     2>       stpw.chg_password ('test');

     3> END;

     4>

ORA-01031: insufficient privileges

ORA-06512: at "SYS.DBMS_SYS_SQL", line 782

ORA-06512: at "SYS.DBMS_SQL", line 32

ORA-06512: at "STPW.CHG_PASSWORD", line 6

ORA-06512: at line 2

 

 

Da die Prozedur unter Definer Rights abläuft, wird auch der ALTER USER Befehl unter den Rechten vom STPW ausgeführt. Dieser darf aber als normaler User, nicht einfach ein Passwort eines fremden Users verändern, was mit der entsprechenden Fehlermeldung angezeigt wird.

 

Ab Oracle 8.1 gibt es eine einfache Lösung für diese Problem: der Einsatz von Invoker Rights !

Was mache ich aber, falls ich mich noch auf einer Oracle 8.0 oder gar Oracle7 Umgebung befinde.

 

Die Prozedur für jeden Anwender in sein eigenes Schema hineinkopieren ? Dies würde das Problem zwar lösen, dafür aber neue Probleme in bei der Software-Wartung und -Verteilung kreieren.

Dem STPW das ALTER ANY USER Recht geben ? Damit würde ich das Problem auch lösen, der STPW könnte aber plötzlich Passwörter von allen Benutzern verändern, was sicher nicht gewünscht ist !

 

Eine andere Möglichkeit besteht in der Verwendung eines undokumentierten Features von Oracle. Damit kann bereits vor Oracle8.1 das Invoker Rights Verhalten bei dynamischem SQL erzwungen werden.

Invoker Rights mit DBMS_SQL

Zum Package DBMS_SQL wird jeweils auch das Package DBMS_SYS_SQL installiert. Dieses Package ist nicht dokumentiert und ist nur in gewrappter Form vorhanden, also unleserlich. Darin versteckt ist eine Prozedur mit dem Namen PARSE_AS_USER, die gerade für das obenbeschriebene Problem sehr hilfreich ist.

 

Diese Prozedur empfängt die gleichen Parameter wie die Prozedur DBMS_SQL.PARSE, hat aber zusätzlich noch einen vierten Parameter USERID. Damit kann beeinflusst werden, unter welchem Benutzer der Befehl geparsed und ausgeführt werden soll. Man kann darüber auch die Userid des Benutzers übergeben und erhält damit die gleiche Funktionalität wie mit den Invoker Rights von Oracle 8.1.

 

Die Prozedur mit Verwendung von PARSE_AS_USER sieht folgendermassen aus:

 

connect stpw/stpw@db1

CREATE OR REPLACE

PROCEDURE chg_password (in_password IN VARCHAR2)

IS

  cur INTEGER;

BEGIN

  cur := DBMS_SQL.open_cursor;

  SYS.DBMS_SYS_SQL.parse_as_user (cur

            , 'ALTER USER ' || USER || ' IDENTIFIED BY ' || in_password

            , DBMS_SQL.native

            , UID);

  DBMS_SQL.close_cursor (cur);

END chg_password;

/

 

Es muss nur der Aufruf von PARSE durch den Aufruf von PARSE_AS_USER ersetzt und die Parameterübergabe ergänzt werden. In diesem Fall wird immer der Wert vom Attribut UID übergeben, d.h. die Prozedur wird nun das Parsen und Ausführen jeweils unter dem angemeldeten Benutzer durchführen.


Damit STPW die Prozedur PARSE_AS_USER verwenden darf, muss er vom SYS das EXECUTE Privileg für das Package DBMS_SYS_SQL erhalten. Dieses ist weder per Default noch über die Rolle EXECUTE_CATALOG_ROLE gesetzt. Zudem besteht kein Public Synonym für DBMS_SYS_SQL, darum ist der Aufruf zusätzlich mit SYS qualifiziert.

 

 

Die Prozedur wiederum unter SCOTT getestet, erzeugt keine Fehler mehr, es hat also funktioniert !

 

SQLWKS> CONNECT scott/tiger@db1

Connected.

SQLWKS> BEGIN

     2>       stpw.chg_password ('test');

     3> END;

     4> /

Statement processed.

 

 

Achtung !!!  Das EXECUTE Privileg für DBMS_SYS_SQL sollte nur sehr restriktiv verteilt werden. Dies gilt auch für das System-Privileg "EXECUTE ANY PROCEDURE". Da bei PARSE_AS_USER als viertes Argument eine beliebige Userid mitgegeben werden kann (z.B. auch 0 für den Benutzer SYS), kann jeder, der das Recht auf PARSE_AS_USER besitzt, darüber problemlos auch SQL Befehle unter SYS ablaufen lassen, was natürlich eine riesige Sicherheitslücke darstellt.

 

In der Praxis könnte diese Problematik über ein zusätzliches Wrapper-Package entschärft werden. Dieses Package kann zum Beispiel ebenfalls eine Prozedur PARSE_AS_USER enthalten, die gegen Aussen den Parameter USERID gar nicht anbietet, diesen dann aber intern hardcodiert auf UID an DBMS_SYS_SQL.PARSE_AS_USER übergibt.

 

PACKAGE BODY dbms_sys_sql_wrapper

IS

 

FUNCTION parse_as_user (c, statement, language_flag)

IS

BEGIN

DBMS_SYS_SQL.parse_as_user (c, statement, language_flag, UID);
END parse_as_user;

 

END dbms_sys_sql_wrapper;

 

Wenn nun das EXECUTE Privileg nur noch auf diesem Wrapper-Package vergeben wird, dann bietet man die Invoker Rights Funktionalität nur noch für den aktuell angemeldeten Benutzer an und nicht für alle Benutzer.

 

Invoker Rights mit Oracle 8.1

Die in diesem Artikel vorgestellte Methode soll, wenn überhaupt, nur noch für Umgebungen vor Oracle 8.1 eingesetzt werden. Ab Oracle 8.1 sollte unbedingt die Variante des Invoker Rights Sicherheitsmodells verwendet werden.

 

Hier die Version der Prozedur CHG_PASSWORD für Oracle 8.1:

 

CREATE OR REPLACE

PROCEDURE chg_password (in_password IN VARCHAR2)

AUTHID CURRENT_USER

IS

  cur INTEGER;

BEGIN

  cur := DBMS_SQL.open_cursor;

  DBMS_SQL.parse (cur

            , 'ALTER USER ' || USER || ' IDENTIFIED BY ' || in_password

            , DBMS_SQL.native);

  DBMS_SQL.close_cursor (cur);

END chg_password;

/

 

 

Die ursprüngliche Lösung muss nur durch den zusätzlichen Befehl AUTHID CURRENT_USER ergänzt werden und schon läuft die Prozedur unter Invoker Rights ab.

 

 

Mehr über die neuen Features von Oracle 8.1 erfahren Sie in unseren aktuellen Seminaren und Kurse.

 

 

Trivadis AG

Guido Schmutz

Papiermühlestrasse 159

CH-3063 Ittigen

Tel: +41 31 928 09 60

Fax: +41 31 928 09 64

Сайт создан в системе uCoz