Wir haben in den letzten Wochen einige Datenbanken von Kunden untersucht und erhebliche Mängel bei der Sicherheit der Daten festgestellt. Primär haben wir uns angeschaut, ob ein Mitarbeiter ohne Weiteres auf die in der Datenbank gespeicherten Daten zugreifen kann. In den meisten Fällen konnte er sich einfach die Backend-Datenbank kopieren und so in den Besitz wichtiger Daten des Unternehmens gelangen. Oft war zumindest das Backend durch ein Kennwort geschützt, sodass man nur über das Frontend auf die Daten zugreifen kann. Ob das sicher ist, schauen wir uns im vorliegenden Beitrag an. Um es vorwegzunehmen: Es ist nicht sicher.
Trügerische Sicherheit? Noch nicht einmal das.
In einer Aktion, bei der wir uns die Datenbanken von Kunden angesehen haben, sind gravierende Sicherheitsmängel aufgetaucht:
- Oft waren die Daten im Backend völlig ungesichert. Da die Benutzer schreibenden Zugriff auf die Backend-Datenbank benötigen, können sie theoretisch leicht die Backend-Datenbank kopieren und auf einen USB-Stick ziehen.
- Teilweise haben wir zumindest per Kennwort geschützte Backenddatenbanken vorgefunden. Die Verknüpfung zu den Tabellen im Backend enthielt dann jedoch das Kennwort in den Verknüpfungseigenschaften, was sich ebenfalls leicht auslesen lässt.
- In den meisten Fällen konnte der Benutzer über den Navigationsbereich direkt auf die verknüpften Tabellen zugreifen. Der Manipulation von Daten wie etwa geleistete Arbeitsstunden oder dem Gehalt sind so leicht möglich, wenn die entsprechenden Tabellen vorliegen.
Aber selbst wenn der Entwickler die Anwendung so weit geschützt hat, dass der Benutzer nicht auf die eingebundenen Tabellen zugreifen kann, lassen sich alle Daten von außen leicht auslesen. In diesem Beitrag zeigen wir, wie das funktioniert. Voraussetzung dafür ist, dass der Benutzer die Frontend-Datenbank geöffnet hat.
Daten auslesen per VBA
Wir legen dazu in einer neuen Datenbank die Prozedur aus Listing 1 an. Die Vorbedingung für ihre Funktion ist:
Public Sub DatenbankAuslesen() Dim db As DAO.Database Dim tdf As DAO.TableDef Dim rst As DAO.Recordset Dim objAccess As Access.Application Dim fld As DAO.Field Set objAccess = GetObject(, "Access.Application") Set db = objAccess.CurrentDb For Each tdf In db.TableDefs If Not Len(tdf.Connect) = 0 Then Debug.Print tdf.Name Set rst = db.OpenRecordset("SELECT * FROM " & tdf.Name, dbOpenDynaset) Do While Not rst.EOF For Each fld In rst.Fields Debug.Print fld.Name; ": ", On Error Resume Next Debug.Print fld.Value, On Error GoTo 0 Next fld Debug.Print rst.MoveNext Loop End If Next tdf End Sub
Listing 1: Auslesen der Inhalte der Tabellen einer anderen geöffneten Access-Datenbank
- Die auszulesende Datenbank ist bereits geöffnet.
- Die auslesende Datenbank mit unserer VBA-Prozedur wird erst danach geöffnet.
In der Prozedur erstellen wir ein Objekt des Typs Access.Application auf Basis des Aufrufs GetObject(, „Access.Application“). Unter den oben angeführten Voraussetzungen sollten wir damit einen Verweis auf die zu untersuchende Datenbank erhalten.
Danach weisen wir der Variablen db einen Verweis auf das Database-Objekt dieser Datenbank zu und durchlaufen die enthaltenen Tabellen. Für alle Tabellen, deren Eigenschaft Connect einen Wert enthält und die wir so als Tabellenverknüpfung identifizieren können, geben wir zunächst den Namen aus.
Danach erstellen wir ein Recordset auf Basis der aktuellen Tabelle und durchlaufen die enthaltenen Datensätze. Dabei geben wir jeweils den Namen und den Inhalt der Felder aus. Wir verwenden noch eine Fehlerbehandlung, wenn sich der Inhalt nicht direkt ausgeben lässt – zum Beispiel für Felder des Typs OLE-Objekt.
Wir können so sehr einfach alle Daten der verknüpften Tabellen im zu untersuchenden Frontend ausgeben.
Das dient nur Beispielzwecken – wenn wir die Daten sichern und beispielsweise in einer eigenen Datei speichern und diese mitnehmen wollten, wäre auch das einfach möglich.
Wir könnten einfach das Datenmodell nachbauen, in dem wir dieses auslesen und in einer neuen Datenbank reproduzieren. Dann können wir Tabelle für Tabelle und Datensatz für Datensatz die gewünschten Informationen in die Zieltabelle übertragen.
Übertragen der Tabellen der geöffneten Datenbank in die Zieldatenbank
Zum Übertragen des kompletten Inhalts einer Datenbank bedarf es gar nicht viel. Wir haben diese Funktion auf drei Routinen aufgeteilt:
- Die erste heißt TabellenUebertragen und ermittelt einen Verweis auf das Database-Objekt der Datenbank mit den zu übertragenden Tabellen und durchläuft die TableDef-Objekte.
- Dabei ruft sie für jede Tabelle die zweite Routine namens TabelleNachbauen auf. Diese kopiert die Tabellen und die enthaltenen Felder Stück für Stück.
- Die dritte Prozedur DatenKopieren überträgt schließlich die Daten der Felder der Quelltabelle in die Zieltabelle.
Die Prozedur TabellenUebertragen
Die erste Prozedur verwendet die bereits bekannte Technik, um einen Verweis auf das Database-Objekt der geöffneten und auszulesenden Datenbank zu erhalten. Außerdem füllt sie eine weitere Database-Variable mit einem Verweis auf die eigene Datenbank (siehe Listing 2).
Public Sub TabellenUebertragen() Dim objAccess As Access.Application Dim dbSource As DAO.Database Dim dbTarget As DAO.Database Dim strSource As String Dim strSQL As String Dim tdfSource As DAO.TableDef Dim tdfTarget As DAO.TableDef Set objAccess = GetObject(, "Access.Application") Set dbSource = objAccess.CurrentDb Set dbTarget = CurrentDb Set dbSource = objAccess.CurrentDb strSource = dbSource.Name Debug.Print strSource For Each tdfSource In dbSource.TableDefs Select Case True Case Left(tdfSource.Name, 4) = "MSys" Case Else Set tdfTarget = TabelleNachbauen(dbTarget, tdfSource) DatenKopieren dbSource, dbTarget, tdfSource.Name, tdfTarget.Name End Select Next tdfSource Application.RefreshDatabaseWindow End Sub
Listing 2: Hauptprozedur zum Einlesen der Daten der aktuellen Datenbank
Dann durchläuft sie alle TableDef-Objekte der Quelldatenbank und prüft bestimmte Eigenschaften des Tabellennamens. Wenn dieser mit MSys beginnt, wird die Tabelle nicht berücksichtigt. Hier können Sie noch weitere Ausnahmen hinzufügen. Für alle anderen Tabellen ruft die Prozedur die beiden Routinen TabelleNachbauen und Datenkopieren auf. Dabei übergibt sie im ersten Fall einen Verweis auf die Zieldatenbank und auf das zu kopierende TableDef-Objekt. Im zweiten Fall übergibt sie Verweise auf Quell- und Ziel-Database-Objekt und den Namen der zu übertragenden Tabelle.
Danach aktualisiert sie noch das Datenbankfenster, damit die zur Zieldatenbank hinzugefügten Tabellen direkt angezeigt werden können.
Die Funktion TabelleNachbauen
Diese Funktion nimmt den Verweis auf die Zieldatenbank sowie das TableDef-Objekt der zu kopierenden Tabelle aus der Quelldatenbank entgegen. Sie löscht zunächst bei deaktivierter Fehlerbehandlung eine gegebenenfalls bereits vorhandene Tabelle mit dem gleichen Namen wie die zu erstellende Tabelle (siehe Listing 3).
Public Function TabelleNachbauen(db As DAO.Database, tdfSource As DAO.TableDef) As DAO.TableDef Dim fldSource As DAO.Field Dim fldTarget As DAO.Field Dim tdfTarget As DAO.TableDef On Error Resume Next db.TableDefs.Delete tdfSource.Name On Error GoTo 0 Set tdfTarget = db.CreateTableDef(tdfSource.Name) For Each fldSource In tdfSource.Fields Set fldTarget = tdfTarget.CreateField(fldSource.Name, fldSource.Type, fldSource.Size) If fldTarget.Type = dbText Then fldTarget.AllowZeroLength = True End If tdfTarget.Fields.Append fldTarget Next fldSource db.TableDefs.Append tdfTarget Set TabelleNachbauen = tdfTarget End Function
Listing 3: Funktion zum Reproduzieren der Tabellen und Felder
Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...
den kompletten Artikel im PDF-Format mit Beispieldatenbank
diesen und alle anderen Artikel mit dem Jahresabo