[ORACLE] Demo: Sicherheit auf Zeilenebene

Exceptionfault

Erfahrenes Mitglied
Ein wichtiges Thema in der Datenbank ist und bleibt die Sicherheit der Daten. Wie stelle ich sicher, dass jeder auch nur das sehen kann was er sehen darf?
Die häufigste Methode ist die Umsetzung einer Sicherheitslogik in der Applikation. Nehmen wir als Beispiel dieses Forum: Über das Login ist der Webapplikation der Benutzer bekannt. Anhand der eindeutigen BenutzerID werden mir in meinem Postfach auch nur meine Nachrichten angezeigt. Was aber, wenn es mir gelingen würde um die Logik der Webapplikation an die Datenbank zu gelangen? Klar, mir stünde die komplette Datenbank offen.
Die Frage ist doch also, wie kann ich die Sicherheit in der Datenbank umsetzen, dass wenn ein Benutzer schon über Umwege in die Datenbank kommt, dass er trotzdem nur zu dem kommt, zu dem er wirklich Zugang haben sollte. Ganz davon abgesehen würde es die Applikationen doch wesentlich vereinfachen wenn man von der Datenbank sowieso nur die Daten bekommt die man grade anzeigen darf...

Ich möchte hier mal eine (wie ich finde) recht gelungene Lösung zeigen, die aber wiedermal nur Oracle Benutzern zu Gute kommt. Die Rede ist vom kostenfreien Feature ROW LEVEL SECURITY. Einzige Voraussetzung ist der Einsatz einer Enterprise Edition und einer Oracle Version >= 9.2.0.

Zunächst unsere Testumgebung:

Code:
CREATE TABLE APP_USERS
(
  USERNAME  VARCHAR2( 35 ) NOT NULL,
  COUNTRY   VARCHAR2(  2 ) NOT NULL
);

INSERT INTO APP_USERS VALUES ( 'MIKE', 'DE' );
INSERT INTO APP_USERS VALUES ( 'JOE',  'US' );

CREATE TABLE APP_DATA
(
  UN_ID    NUMBER(  5,0 ) NOT NULL,
  COUNTRY  VARCHAR2(  2 ) NOT NULL,
  DATAFLD  VARCHAR2( 50 ) NOT NULL
);

INSERT INTO APP_DATA VALUES (  1, 'DE', 'Das sind geheime Daten!' );
INSERT INTO APP_DATA VALUES (  2, 'DE', 'Nur Mike darf sie sehen!' );
INSERT INTO APP_DATA VALUES (  3, 'US', 'Joe hat auch geheime Daten!' );
INSERT INTO APP_DATA VALUES (  4, 'IT', 'Geheimes Pizzarezept... ;-)' );

COMMIT;

CREATE USER MIKE IDENTIFIED BY mike DEFAULT TABLESPACE USERS TEMPORARY TABLESPACE TEMP;
CREATE USER JOE  IDENTIFIED BY joe  DEFAULT TABLESPACE USERS TEMPORARY TABLESPACE TEMP;
CREATE USER BILL IDENTIFIED BY bill DEFAULT TABLESPACE USERS TEMPORARY TABLESPACE TEMP;

GRANT CREATE SESSION TO MIKE;
GRANT CREATE SESSION TO JOE;
GRANT CREATE SESSION TO BILL;

GRANT SELECT, INSERT, UPDATE, DELETE ON APP_DATA TO MIKE, JOE, BILL;

Wir haben also 2 Tabellen und drei Benutzer. Die Datenbank erlaubt keinem der User Zugriff auf die Tabelle APP_USERS, dafür aber vollen Zugriff auf APP_DATA. Wenn sich Bill nun also anmeldet sieht er folgendes:

Code:
SQL> conn bill/bill
Connected.
SQL> select * from rls.app_data;

     UN_ID CO DATAFLD
---------- -- --------------------------------------------------
         1 DE Das sind geheime Daten!
         2 DE Nur Mike darf sie sehen!
         3 US Joe hat auch geheime Daten!
         4 IT Geheimes Pizzarezept... ;-)

Nicht so gut...
Wir brauchen also eine Funktion, die unsere daten für den passenden User einschränkt. Und diese Funktion sieht ganz einfach aus:
Code:
CREATE OR REPLACE FUNCTION app_data_sec (object_schema IN VARCHAR2, object_name VARCHAR2) 
RETURN VARCHAR2 
IS
  v_country  APP_USERS.COUNTRY%TYPE;
BEGIN
  SELECT  COUNTRY
  INTO    v_country
  FROM    APP_USERS
  WHERE   USERNAME = USER;

  RETURN  'COUNTRY = ''' || v_country || '''';

EXCEPTION
  WHEN NO_DATA_FOUND THEN
    RETURN '1=2';
END;
/
Wir selektieren das Land des gerade angemeldeten Benutzers aus der APP_USERS Tabelle und geben einen String zurück der einer "WHERE" Klausel recht nahe kommt.
Nun müssen wir die Funktion noch an die Tabelle binden:
Code:
BEGIN
  dbms_rls.add_policy(	
    object_schema => 'RLS',
    object_name => 'APP_DATA',
    policy_name => 'APP_DATA_POLICY',
    function_schema =>'RLS',
    policy_function => 'APP_DATA_SEC'
  );
END;
/
Und hier das Ergebnis:
Code:
SQL> conn mike/mike
Connected.
SQL> select * from rls.app_data;

     UN_ID CO DATAFLD
---------- -- --------------------------------------------------
         1 DE Das sind geheime Daten!
         2 DE Nur Mike darf sie sehen!

SQL> conn joe/joe
Connected.
SQL> select * from rls.app_data;

     UN_ID CO DATAFLD
---------- -- --------------------------------------------------
         3 US Joe hat auch geheime Daten!

SQL> conn bill/bill
Connected.
SQL> select * from rls.app_data;

no rows selected
Und die Überraschung:
Code:
SQL> conn rls/rls
Connected.
SQL> select * from app_data;

no rows selected

SQL> conn system/oracle
Connected.
SQL> select * from rls.app_data;

no rows selected

SQL> conn / as sysdba
Connected.
SQL> select * from rls.app_data;

     UN_ID CO DATAFLD
---------- -- --------------------------------------------------
         1 DE Das sind geheime Daten!
         2 DE Nur Mike darf sie sehen!
         3 US Joe hat auch geheime Daten!
         4 IT Geheimes Pizzarezept... ;-)
Die Policy gilt also auch für den Besitzer der Tabelle und sogar für den User System. Lediglich SYS sieht alles. Dadurch dass auch System eingeschränkte Rechte hat, würde er bei einem Export der Daten mit dem Tool "exp" auch keine Daten bekommen, also Sicherheit auf der tiefsten Ebene.

Ich hoffe ich habe ein interessantes Thema angeschnitten, bei Fragen helfe ich natürlich gerne weiter.
 
Hallo!

Wie wärs denn mal mit einem "Tutorial" zum Thema locking in Oracle?
Row-Level Locking
Table Level Locking
Select for update
Deadlock
Wie findet man heraus wer welche Tabelle/Zeile gelockt hat und wie sieht man wer auf die Freigabe des Locks wartet...
:)

Gruß Tom
 
Hi,

das würde mich sehr interessieren.
Vorallem die Suche von Deadlocks, bzw. gelockte Tabellen.
Wäre schön, wenn das mal einer Verfassen könnte. :D
 

Neue Beiträge

Zurück