In diesem Blog-Artikel wird aufgeführt, wie mit einfachen SQL Statements das Feature Dynamic Data Masking ausgetrickst werden kann. Dynamic Data Masking steht seit der SQL Server Version 2016 zur Verfügung.
Für die Demos wird die SQL Server Version 2016 (RTM) verwendet. Dies bedeutet, dass hier keine Services Packs oder kumulative Updates eingespielt wurden. Innerhalb des Artikels werden Hinweise aufgeführt, inwiefern die Demos mit Service Pack 1 noch funktionieren oder ob Microsoft hier Nachbesserungen eingespielt hat.
Maskierung anwenden:
Zunächst ist eine Beispiel-Tabelle (dbo.Kunden) mit sechs Datensätzen erstellt worden. Zusätzlich sind auf folgende Spalten unterschiedliche Dynamic Data Masking Funktionen angewendet- Nachname nvarchar(25) --> FUNCTION = 'partial(1,"XXXXX",2)'
- Kreditkartennummer nvarchar(25) --> FUNCTION = 'partial(0, "XXXX-XXXX-XXXX",4)'
- Anzahl_Buchungen int --> FUNCTION = 'default()'
- Guthaben money --> FUNCTION = 'default()'
- EmailAdress nvarchar(50) --> FUNCTION = 'email()'
- PhoneNumber nvarchar(25) --> FUNCTION = 'default()'
Alle nachfolgenden Demos werden unter dem Benutzer MaskingUser durchgeführt, welcher die Datensätze, durch die fehlende Berechtigung, nur maskiert sehen kann.
Der Benutzer wird mit dem nachfolgenden Befehl erstellt.
Der Benutzer MaskingUser hat keine UNMASK-Berechtigung. Das Ergebnis für MaskingUser ist unter Abbildung 2 zu sehen. Hier ist zu erkennen, dass alle Spalten eine entsprechende Maskierung, je nach Maskierungs-Funktion haben.
Maskierung durch WHERE-Bedingungen aushebeln:
Mittels einer einfachen WHERE-Abfrage kann der Benutzer die Maskierung in der Ausgabe zwar nicht aufheben, er gelangt jedoch an den korrekten Wert innerhalb der WHERE-Klausel (siehe Abbildung 3). Sicherlich muss der Benutzer hier etwas Aufwand betreiben, da er jedes Zeichen innerhalb der WHERE-Bedingung mit Wildcards überprüfen muss. In diesem Beispiel hat der Benutzer den korrekten Nachnamen (‚Beck') in die WHERE-Klausel eingetragen und erhält somit ein Ergebnis im Resultset.
Maskierte Integer Werte unmaskiert anzeigen:
Auch das Auslesen von Integer-Datentypen ist möglich. Hierzu wird eine Hilfstabelle benötigt. Die Hilfstabelle hat eine Spalte, in der Zahlen von 1-10000 pro Zeile eingetragen sind.
In diesem Beispiel wird ein INNER-JOIN auf die Hilfstabelle durchgeführt und die korrekten Werte in der Spalte Anzahl_Buchungen_Unmasked ausgegeben. Hierbei handelt es sich um die Spalte aus der Hilfstabelle. Der Benutzer hat auf der eigentlichen Tabelle (dbo.Kunden) nicht das Recht die Spalte Anzahl_Buchungen unmaskiert zu sehen, welches im Result-Set durch diese Spalte bestätigt wird.
Maskierte Integer/Money Werte unmaskiert anzeigen:
Hinweis: Funktioniert mit SQL Server 2016 SP1 ebenfalls, mit SP1 und CU 4 jedoch nicht mehr!
Eine weitere Möglichkeit bei INTEGER- und MONEY-Datentypen ist das Verwenden von internen Funktionen. Da der SQL Server sowohl eine Wurzel-Funktion (sqrt) als auch eine Quadrat-Funktion (square) bietet, können beide verwendet werden, um die ursprüngliche Zahl herauszufinden (siehe Abbildung 5).
Maskierte Strings unmaskiert anzeigen:
Hinweis: Funktioniert auch mit SQL Server 2016 SP1 CU4.
Auch maskierte Strings können mit einer Hilfstabelle im Klartext angezeigt werden. Im ersten Beispiel (Abbildung 6) wird die erste Ziffer der jeweiligen Kreditkarte ausgegeben. Hierzu wird die SUBSTRING Funktion verwendet und aus der Spalte dbo.Kunden.Kreditkartennummer das erste Zeichen ausgelesen. Anschließend wird noch die ASCII-Funktion verwendet, sodass die Ausgabe als Zahl erfolgt.
Die erste Möglichkeit liefert damit allerdings nur das erste Zeichen der Kreditkarte zurück. Mit dieser Information kann aber jetzt weiter ins Detail gegangen werden.
Mit einem zusätzlichen CROSS JOIN auf die Hilfstabelle wird jeder Datensatz mit einer aufsteigenden Zahl versehen. Somit wird der Datensatz mit der KundenID=21817 vierzehnmal gejoint, da die Kreditkartennummer 14 Zeichen enthält. Zum besseren Verständnis ist die entsprechende Spalte (TBL_Laenge.numbers AS laenge) mit in die Ausgabe des SELECT-Statements aufgenommen worden. Diese Spalte wird im nächsten Schritt in der SUBSTRING Funktion als Startposition verwendet.
Für eine bessere Verarbeitung wird das Ergebnis in eine temporäre Tabelle mittels SELECT INTO Befehl geschrieben. Eine Abfrage auf die temporäre Tabelle liefert jetzt pro KundenID und pro laenge (also Position) die korrekte Zahl der Kreditkartennummer. (Abbildung 7)
Um die einzelnen Kreditkartenzahlen pro KundenID in eine Zeile zu bekommen, wird sich jetzt der XML-Funktion des SQL Servers bedient. (Abbildung 8)
Eine ausführliche Beschreibung für die hier verwendete XML-Funktion ist hier zu finden.
Zusammenfassung
Mit etwas Aufwand kann ein Benutzer die Funktion von Dynamic Data Masking umgehen. Im ersten Beispiel benötigte der entsprechende Benutzer nur Leseberechtigungen auf der Tabelle. Jetzt kann verständlicherweise gesagt werden, dass der Benutzer für alle weiteren Beispiele das Recht benötigt, eine Hilfstabelle anlegen zu dürfen. Für diese Beispiele trifft die Aussage zu. Der Benutzer kann jedoch auch einfach eine temporäre Tabelle anlegen. Dieses Recht muss ihm nicht explizit gegeben werden.
Mit diesem Artikel soll aufgezeigt werden, dass hinter Dynamic Data Masking ein schickes Feature steckt, jedoch mit sehr einfachen Mitteln das Ganze ausgetrickst werden kann. Sicherlich arbeitet Microsoft schon mit Hochdruck an der Verbesserung dieser Probleme.