25. Februar 2011

Data theft: Monitor only selects with a resultset higher than 30

Oft haben meine Kunden eine genaue Vorstellung ihre Datenbanken zu überwachen. Ein gemeinsamer Nenner unterschiedlicher Kunden ist der Wunsch alle SELECTS zu kennen, die eine bestimmte Menge von Datensätzen selektiert haben:
sagen wir mal alle SELECT where SQL%ROWCOUNT > 30

Warum will man das wissen?
Dieser Wunsch ist ganz einfach zu beantworten. In der Regel nutzen die Endanwender Anwendungen wie z.B. Oracle Forms oder SAP oder andere Standardanwendungen. Durch die Anwendungen bekommt man i.d.R. einen Datenzugriff auf die Datenbank und kann Veränderungen an den Daten vornehmen. In der Regel arbeitet man genau auf einen Datensatz. Wenn man nun alle SELECTS kennt, die eine Ergebnismenge > 30 Datensätze ermittelt haben, kann  man davon ausgehen, dass eine höhere Wahrscheinlichkeit eines Datendiebstahls vorliegt.

Was erzähle ich nun diesen Kunden?
Die Lösung für diesen Wunsch ist nicht so trival zu beantworten.
Viele kennen bestimmt die interne DB-Variable SQL%ROWCOUNT, die man in PL/SQL nutzen kann, um z.B. die Anzahl aller veränderenden Datensätze durch ein UPDATE zu ermitteln. Diese Variable hilft uns hier leider nicht weiter.
Ich denke hier an zwei Lösungen:
1. Alternative: Nutzung der V$-Views
Also Informationen aus der SGA lesen und auswerten. Mit dieser Variante können wir alle aktuellen Abfragen direkt aus dem DB-Speicher lesen.
Vorteile: Die V$-Views bieten alle Informationen, die wir benötigen. Mit dem nachliegenden Statement kann ich alle Informationen auslesen, die ich brauche.
select vsql.last_active_time,
 vsql.parsing_schema_name, 
 vsess.osuser,
 vsess.machine,
 vsess.program,
 vsql.rows_processed, 
 vsql.sql_text
 from v$sqlarea vsql, v$session  vsess
 where command_type = 3 
 and trunc(last_active_time) = trunc(sysdate)
 and rows_processed >= 30
 and vsql.address = vsess.SQL_ADDRESS
 order by vsql.last_active_time desc 
Das Ergebnis dieser Überwachung würde so aussehen:

Nachteile: Die Nachteile liegen auf der Hand: Der Speicher also die V$-Views ändern sich u.U. sehr schnell, so dass man nicht alle Informationen im dauernden Zugriff hat. Man müßte einen Weg finden, die Informationen aus den V$-Views permanent abzuspeichern. Ausserdem zeigt das SQL-Statement einen Join auf die V$SESSION View. D.h. die Session in der Datenbank muss noch aktiv sein. Würde man einen Outer Join auf diese View machen, also

and vsql.address = vsess.SQL_ADDRESS (+)

So würde man bei nicht aktiven Session wenigsten das SQL-Statement sehen, hätte aber keine Informationen zu dem Benutzer. Ein weitere Nachteil ist: Alle Informationen in V$Views werden nicht permanent abgespeichert, so dass man die Informationen nicht dauerhaft zur Verfügung hat. Würde man sich für diese Alternative entscheiden, so sollte man für die Aufbewahrung der Informationen einen Speicher Dump machen (z.B. oradebug dumpsga oder oradebug dump library_cache ). Wobei diese Dumps schwer zu lesen sind und das weitere Handling nicht trival ist.

So kommen wir nun zu der 2. Alternative

2. Alternative: Datenklassifizierung und bei Bedarf auswerten
Bevor man mit dieser Anforderung startet, sollte man sich überlegen, welche Daten habe ich in meiner Datenbank und würde die Art der Daten klassifizieren. D.h. z.B. meine Personendaten in der Tabelle scott.emp werden als "Top Secret" klassifiziert.
Nun kann man die Objekte, die sensible Daten beinhalten (also Daten, die Top Secret sind) überwachen. Das kann die Oracle Datenbank tun. Hierfür schaltet man ein Audit ein.
audit all on scott.emp;
Mit diesem Schalter werden alle Aktivitäen auf der EMP-Tabelle in die interne Audit-Tabelle (AUD$) der Datenbank protokolliert. Eine bessere Übersicht erhält man durch Nutzung der Audit-View DBA_AUDIT_TRAIL. Hier befinden sich alle Informationen, die man für eine weitere Untersuchung benötigt.

Nun haben wir erreicht, dass alle Aktivitäten auf unserer sensiblen Tabelle protokolliert werden, also auch die SQL-Statements. Jetzt kann ich sofort nach Einfügung eines Audit-Datensatzes reagieren. Das protokollierte SELECT Statement wird ausgewertet und der Rowcount bestimmt. Man kann einen Alert generieren, wenn die Ergebnismenge > 30 ist. Ich habe dies im nachfolgenden Script nur ein wenig angedeutet:
Schaltet man Oracle Audit Vault an, dann werden alle protokollierten Daten in ein revisionssicheres Repository übertragen und kann für spätere Auswertungen und der Beweisführung genutzt werden.

Also wie gesagt, dieses Thema ist nicht trival. An Kommentaren und Hinweisen bin ich sehr interessiert.

Kommentare:

  1. Hallo Herr Mützlitz,

    interessanter Artikel. Sie sprechen aber hier viel mehr den Fall, wenn der Endbenutzer der Datenbank bekannt ist, nicht wahr? Denn viele Anwendungen auch die SAP, die Sie in Ihrem Artikel erwähnten, greifen ja mit einem Schema-User an die Oracle Datenbank. Was dann? Ich weiß dann lediglich, dass jemand versucht hat an die Daten ranzukommen, aber ihn herausauszufinden wird wohl schwer sein. Bei SAP könnte man neuerdings (ab der Version 7.1) den client_identifier an die Datenbank weiterreichen und somit den Endbnutzer ausfindig machen. Aber was mache ich mit den anderen WebAnwendungen?

    Grüße

    AntwortenLöschen
  2. Hallo Anonym,
    typischerweise übernimmt die Applikation den Zugriffsschutz auf die Datenbank. Und viele moderne Anwendungen können in der Datenbanksession einen End-User Context (was sie hier ansprechen) setzen, über den ich den tatsächlichen Enduser bestimmen kann. Wenn die Applikation eine nicht vorgesehene Selektierung von vielen Daten ermöglicht (z.B. mittels SQL-Injection) dann würde ein Context hilfreich sein, wenn die Anwendung nur einen Anwendungsuser benutzt.
    Ich interesse mich aber vielmehr für die Zugriffe auf die Datenbank, die nicht über die entsprechende Applikation stattfinden. Sondern Tools wie SQL Developer, Toad oder SQL*Plus nutzen. Hierüber finden die Datendiebstähle statt. Und in diesen Fällen hat man tatsächlich einen realen DB-Nutzer.

    AntwortenLöschen