SQL Server 2016: Was ist neu? – Teil 1: Security
Microsoft hat in den letzten Jahren bei der Entwicklung ihrer Datenbank-Serverlösung "SQL Server" einen Zahn zugelegt. Versionen werden in immer kürzer werdenden Abständen veröffentlicht. Ein Grund dafür ist der veränderte Fokus des (inzwischen nicht mehr neuen) Chefs Satya Nadella auf das "Mobile First, Cloud First"-Prinzip. Herr Nadella setzt insbesondere auf die Microsoft Cloud Computing-Lösung "Azure". Hier soll ein immer größer werdender Anteil der Umsätze gemacht werden. Alle Infrastruktur- und Applikationslösungen bei Microsoft müssen entweder überarbeitet oder ganz neu entwickelt werden, um dieses ehrgeizige Ziel zu erreichen.
Der veränderte Fokus führte bei Microsoft zu einer stärkeren Investierung in die Cloud-Dienste und demnach in SQL Server. Da Microsoft nun seine eigenen Produkte nicht nur stärker intern nutzte, sondern auch als Cloud-Platform anbieten wollte, war der Druck, die Produkte a) zu verbessern und b) schneller/agiler zu entwickeln, deutlich gestiegen. Die Entwicklung von zwei unterschiedlichen Versionen des SQL Servers (On Premises und Cloud) war auf Dauer nicht tragbar. Es wurde deshalb entschieden, die Entwicklungsstränge von SQL Server 2014 und Azure SQL Database zusammenzuführen. Seitdem sind die zwei Produkte vereint und alle Features werden sowohl für die Cloud als auch für On-Premises entwickelt. Diese Tatsache führt dazu, dass alle Features, die im SQL Server 2016-Release neu sind, bereits seit längerer Zeit in der Cloud-Version existieren.
Schnellere Entwicklung sowie kürzere Release-Zyklen erlauben es Microsoft (und uns als Kunden/Benutzer) davon zu profitieren, dass nicht mehr jahrelang auf Verbesserungen gewartet werden muss. Die Kehrseite der Medaille ist, dass wir uns stärker darum kümmern müssen, dass wir mit der Entwicklung von SQL Server Schritt halten. Alte Software muss mitgeschleppt oder ersetzt werden. Viele Kunden fragen sich: Welche Teile des SQL Servers sind überhaupt für meinen Einsatzbereich wichtig?
In dieser Serie werde ich die Technologien aus vier Bereichen des SQL Servers erklären, von denen ich meine, dass sie für viele Benutzer für eine längere Zeit von Nutzen sein werden.
Es werden folgende vier Bereiche untersucht und die wichtigsten Features und deren Einsatzmöglichkeiten dargestellt:
- Security
- Engine Features
- Programmierung
- Hochverfügbarkeit
In dieser Folge der Neuerungen bei SQL Server 2016 werden wir uns also auf die Sicherheitsaspekte konzentrieren. Security ist (zu Recht) immer noch ein wichtiges Thema in der IT und hier hat Microsoft ganze Arbeit geleistet. Beim Azure SQL Database wurde Microsoft aufgefordert, Datensicherheitsgesetze einzuhalten, z. B. HIPAA [1], PCI DSS [2] und ISO 27001 [3]. Diese Anstrengungen seitens Microsoft, flossen von Azure SQL Database in den "normalen" (On-Premises) SQL Server und mündeten teilweise in den weiter unten erklärten Features. So wie bei allen Security-Lösungen, gilt hier ebenfalls die Devise "Defense in Depth". Das heißt, man baut die Verteidigung eines Systems in mehreren Schichten auf; jede Schicht erhöht die Sicherheit des Systems und erschwert ungewollte Fremdzugriffe.
Row Level Security
Die Row Level Security dient zur Steuerung des Zugriffs auf schützenswerte Daten, indem sie einzelne Datensätze filtert. Als Einsatzbeispiel nehmen wir ein Kundenmanagementsystem. Dort wollen wir den Zugriff auf unterschiedliche Kundengruppen einschränken, damit zwei Vertriebsmitarbeiter nur ihre Kundengruppen sehen können. Normalerweise müsste man die Applikations- bzw. Datenbanklogik ändern, was oft teuer oder gar unmöglich ist (z. B. bei Fertiglösungen von Drittanbietern). Mit Row Level Security ist es nun möglich, völlig transparent bei allen anderen Applikationen eine automatische Filterung vorzunehmen. Diese Filterung kann sowohl eine einfache Logikabfrage auf eine Spalte der Quelltabelle sein, als auch eine kompliziertere Logikabfrage, die auf Steuerungstabellen zugreift. Sobald man diese Filterlogik definiert hat, werden Datensätze bei jedem Datenbankzugriff erneut gegengeprüft und Daten werden bei Bedarf ausgefiltert. Einer der Vorteile hierbei ist es, eine Datensicherheitsfunktion in die Datenbank einzubetten, die bei allen Applikationszugriffen agiert; egal, ob der Zugriff von einer "erlaubten" Applikation stammt oder aus einer Excel-Tabelle aus der Controllingabteilung, von der keiner etwas weiß. Solange die Filter richtig aufgebaut sind, werden Systembenutzer nur auf die Daten zugreifen können, die sie tatsächlich sehen dürfen.
In Abb.1 sehen wir eine klassische Applikation mit Datenbankzugriff (sehr vereinfacht dargestellt). Die Applikation schickt Anfragen an den Datenbankserver und erhält die Daten als Antwort. Da die Applikation von einem Drittanbieter eingesetzt wird, der keine Erweiterungen für das Produkt mehr anbieten kann, wäre es unmöglich, die gewünschte Filterung der Daten zu bekommen.
Mit SQL Server 2016 und Row Level Security kann man nun, wie in Abb.2 zu sehen, diese Applikationsanfragen beeinflussen, ohne die Abfragen oder den Applikationscode verändern zu müssen.
- Schritt 1 ist das Entgegennehmen der Abfrage und die Identifizierung, dass es sich um eine Tabelle handelt, bei der eine Security Policy angewendet wurde.
- Die Schritte 2 und 3 stellen die Anwendung des Filters und das Umschreiben der Abfrage dar.
- Zum Schluss kommt Schritt 4, in dem die Daten gefiltert abgefragt werden.
Die Applikation hat diese Transformation überhaupt nicht mitbekommen, da dieser Prozess komplett innerhalb der Datenbank stattfindet. Dank der vordefinierten Filter Policy werden einfach bestimmte Datensätze nicht an die Applikation zurückgeliefert. So wäre es bei unserem Beispiel relativ einfach, den zwei Vertriebsmitarbeitern eine gefilterte Sicht der Bestelldaten zu geben.
Aber...... Es ist nicht alles Gold was glänzt
Wir haben gesehen, dass die Security auf Reihenebene durch einen Funktionsaufruf bei jedem Tabellenzugriff ermöglicht wird. Der ein oder andere Leser hat sicherlich schmerzhafte Erfahrungen mit Funktionen und großen Datenabfragen sammeln dürfen. Sind die Funktionen für Row Level Security suboptimal geschrieben oder ungünstig angewendet, ist es sehr einfach, ein sonst schnelles System lahmzulegen. Hier gilt es vorher zu prüfen, ob, was und wie genau gefiltert werden soll. Jeder Funktionsaufruf der verhindert werden kann, bedeutet ein Plus für die Systemperformance.
Wie eingangs erwähnt, gilt auch bei Row Level Security, dass Security aus mehreren Schichten bestehen muss, um schützenswerte Daten sicher aufbewahren zu können. Es ist als Systemadministrator möglich, diese Security Policies auszuschalten, um anschließend die Filterung auszuschalten. Es ist ebenfalls möglich unter bestimmten Umständen Informationen abzuleiten, selbst, wenn sie ausgefiltert werden. Letztendlich sind solche Security Features selten singulär einzusetzen, sondern meist zusammen mit anderen Funktionen, damit das gesamte System sicherer wird.
Always Encrypted
Das "Prinzip der geringsten Befugnisse" [4] sieht vor, dass ein Benutzer (oder auch Administrator) nur die Rechte oder Befugnisse erhalten soll, die ausreichen, um seine Arbeit verrichten zu können. Für einen Datenbankadministrator ist es wichtig, das System betreuen zu können, nicht aber, dass er die Dateninhalte des Systems sehen kann.
Bei früheren Versionen des SQL Servers waren die Daten innerhalb des Servers in Gänze von einem Systemadministrator einsehbar. Das mag bei vielen Firmen immer noch in Ordnung sein. "Wir vertrauen unseren Mitarbeitern. Warum sollten sie nicht ungehindert ihrer Arbeit nachgehen können?". Dieses Vertrauen ist wichtig und richtig. Nur was passiert, wenn die Systeme ausgelagert werden? Entweder durch Outsourcing (was immer beliebter wird) oder durch die "neue" Lösung, durch Cloud-Computing. Beim Outsourcing der Mitarbeiter gehen viele "Sicherheiten" verloren. Die "Schlüssel" der Systeme werden regelrecht aus der Hand gegeben; da nimmt man die Rolle des Mitfahrers/Passagiers ein. Bei der Cloud-Computing-Lösung hat man nur bedingt Kontrolle über die Systeme. Wie der Versuch der US-Regierung Microsoft, durch das Verklagen von Microsoft [5] an Daten aus der Cloud heranzukommen, zeigte. Zum Glück wurde die Klage abgewiesen. Aber was kann man dagegen unternehmen, wenn Microsoft (oder Clouddienstanbieter XY) gezwungen wird, Daten auszuhändigen?
Werden die Daten in der Cloud- oder beim Outsourcing-Anbieter verschlüsselt gespeichert, erhöht sich die Sicherheit wieder deutlich. Hierzu kann und muss man wieder mehrere Technologien bewerten. Eine vollständige Festplattenverschlüsselung ist schon ein guter Start und besonders bei virtuellen Maschinen eine gute Lösung, da man bis auf die Betriebssystemebene Kontrolle hat. Da werden die Daten, die auf einem System landen, beim Speichern verschlüsselt abgelegt und sind vor den bereits erwähnten Klagen etwas mehr geschützt.
Was tut man aber bei den "Database as a Service"-(DaaS)-Lösungen, bei denen man nicht das Betriebssystem kontrolliert, sondern nur eine Datenbank? Werden die Datenbanksicherungen sicher aufbewahrt und verschlüsselt? Das weiß man einfach nicht. Bis SQL Server 2016 wurden die Lösungen für dieses Problem darin gesehen, mit Spaltenverschlüsselungen zu arbeiten. Dabei wurden wichtige Teile des Verschlüsselungsprozesses innerhalb der Datenbank gespeichert und stellten zusätzliche Angriffsflächen dar.
Um sicher zu gehen, dass gar keine Entschlüsselungsteile dauerhaft in der Datenbank gespeichert werden, ist eine Verschlüsselung außerhalb des Datenbanksystems notwendig. Hier kommt Always Encrypted ins Spiel. Microsoft bietet innerhalb des .Net Frameworks und der darin enthaltenden SQL-Clients die Möglichkeit, mit wenigen Schritten all das zu verschlüsseln, was zum SQL Server geschickt wird.
In Abb.3 wird dargestellt, wie Always Encrypted funktioniert. Eine Abfrage wird auf Clientseite vorbereitet. Auf dem Weg zum SQL Server werden die schützenswerten Daten mit der "ADO.NET"-Bibliothek auf Clientseite verschlüsselt (die Abfrage bleibt unverschlüsselt, die CustId-Wert wird verschlüsselt). Die Abfrage wird ausgeführt und die verschlüsselten Daten werden an den Benutzer zurückgeliefert, wo sie wieder von der "ADO.NET"-Bibliothek entschlüsselt und dargestellt werden.
Die Daten werden mithilfe von Always Encrypted niemals unverschlüsselt auf dem SQL Server gespeichert. So ist es möglich, ungewollten bzw. unerlaubten Datenzugriffen entgegenzuwirken. Wenn nur verschlüsselte Daten in der Datenbank sind, ist es deutlich weniger kritisch, sollte es der NSA tatsächlich gelingen auf Daten Zugriff zu erlangen. Es ist höchst unwahrscheinlich, dass gestohlenes Datenmaterial, das verschlüsselt ist, von Fremdorganisationen entschlüsselt und genutzt werden kann.
Wie bei Row Level Security, sind die Vorteile bei Always Encrypted mit Kosten verbunden. Die Verschlüsselung von Daten kostet CPU-Zeit, wobei CPU heutzutage im Überfluss vorhanden ist. Wo diese Verschlüsselung schmerzhaft sein kann, ist bei der Abfrage von Daten in SQL Server. Je nachdem welche Art der Verschlüsselung [6] gewählt wurde, können bestimmte Optimierungen oder sogar Abfragemethoden (order by, join) in SQL Server nicht benutzt werden. Diese Einschränkungen können bei großen Datenmengen tatsächlich Schwierigkeiten bereiten. Hier schlägt das berühmte "Project Management Triangle" [7] in leicht abgewandelter Form zu: "Wähle zwei Optionen aus: Schnell, Günstig und Sicher." Da wir sicher sein wollen, müssen wir entweder auf Performance oder auf eine günstige Lösung verzichten.
Dynamic Data Masking
Dynamic Data Masking wurde entwickelt, um bestimmte Daten bei Abruf zu verschleiern. Das bedeutet, dass die Daten an sich nicht geändert werden, sondern lediglich die Anzeige der Daten.
Dieser Art der Verschleierung wird dann angewendet, wenn bestimmte Spalten in Tabellen nur von einem eingeschränkten Personenkreis gelesen/gesehen werden dürfen. In früheren Versionen von SQL Server konnte man eine View anlegen und Spalten ein- oder ausbauen. Es war auch möglich, eine Verschlüsselung von einzelnen Spalten vorzunehmen, aber das verändert zwangsläufig die Daten beim Speichern und nicht nur die Anzeige.
Um eine "Maske" zu definieren, müssen die Spalten, die wir verschleiern wollen, mit einer weiteren Eigenschaft erweitert werden. Die Eigenschaft masked with wird hinter den Datentyp der Spaltendefinition angehängt.
In Abb.4 sehen wir eine Tabelle mit fünf Spalten; vier davon haben eine Maskierung definiert. Es gibt, wie oben zu sehen, die Möglichkeit, die Maskierungsfunktion zu beeinflussen. Die default-Funktion zeigt eine von Microsoft definierte Standardausgabe, die für die unterstützten Datentypen automatisch angewendet wird. Zusätzlich dazu gibt es noch die Funktionen email, partial und random; bis auf random sind die Funktionen in Abb.4 zu sehen. Diese Funktionen wurden während der Betaphase von SQL Server 2016 erweitert und verbessert. Die Einschränkungen der Funktionen und unterstützte Datentypen finden Sie bei Books Online.
Sobald die Maskierung definiert wurde, werden die Daten bei einer Abfrage, so wie in Abb.4, nur bei der Anzeige verschleiert. Die Entscheidung, ob ein Benutzer die verschleierten Daten sehen darf, wird derzeit auf Datenbankebene gesteuert. Das heißt, ein Benutzer darf derzeit entweder alle verschleierten Daten in einer Datenbank sehen oder gar keine. Die Granularität der Berechtigung ist also noch nicht ganz ausgereift. Meine Hoffnung ist es jedoch, dass Microsoft bis auf Spaltenebene die Berechtigungen steuern lassen wird. Es muss sich zeigen, ob und wie Microsoft dieses Berechtigungskonzept weiterentwickelt.
Diese Maskierung greift bei allen Datenbankzugriffen, egal ob per T-SQL in SQL Server Management Studio, ob per Excel-Pivottabelle oder mit einer gewöhnlichen .Net-Applikation. Wenn die Berechtigung, die Daten zu sehen, nicht vorhanden ist, werden nur verschleierte Werte angezeigt. So können wir sicher sein, dass alle Benutzer nur die Spalteninhalte sehen können, die sie tatsächlich sehen dürfen.
Fazit
Microsoft hat mit SQL Server 2016 einige wichtige neue Funktionen eingebaut, um die Sicherheit der Dateninhalte zu erhöhen. Da Security mit mehreren Schichten aufgebaut werden muss, ist jede weitere Schicht ein wichtiger und guter Zusatz zu dem Gesamtsystem.
Wie immer in der IT-Welt sollte man aber nicht versuchen, die oben erwähnten Technologien zu nehmen und nach einem Problem zu suchen. Im Gegenteil: Man sollte lieber die Probleme im Arbeitsalltag identifizieren und dann nach einer Lösung suchen. Ein Sicherheitsproblem kann durch Row Level Security, Always Encrypted und Dynamic Data Masking gelöst werden. Desweiteren lassen sich mithilfe dieser Funktionen auch Sicherheitsprobleme lösen, die eventuell im Nachhinein auftreten könnten. Auf jeden Fall hat man durch diese drei Features gute "Werkzeuge" an der Hand, die einem helfen können, sollte es einmal zu Schwierigkeiten kommen.
Im Anhang zu diesem Artikel sind Beispiele von Row Level Security und Dynamic Data Masking verfügbar. Ein Beispiel für Always Encrypted wird von Microsoft auf GitHub mit dem "Wide World Importers"-Projekt angeboten [8].
Dies ist der erste von vier Artikeln von William Durkin über die Neuheiten von SQL Server 2016. Die weiteren Artikel der Serie (Engine Features, Programmierung und Hochverfügbarkeit) erscheinen in den nächsten Wochen.
Anhang
Folgend finden Sie Beispiele/Demonstrationen für Row Level Security und Dynamic Data Masking:
SET NOCOUNT ON
GO
-- Wir arbeiten in tempdb, weil wir nur "spielen" :)
USE tempdb
GO
-- Erst aufräumen. Hier sehen wir den neuen Befehl "DROP IF EXISTS"
DROP TABLE IF EXISTS dbo.Orders, dbo.SalesPerson
DROP USER IF EXISTS SalesNorth
DROP USER IF EXISTS SalesSouth
GO
-- Nun bauen wir unsere Testtabelle frisch auf
-- Die Tabelle wird für Demozwecken einfach gehalten
CREATE TABLE dbo.Orders
(
CustomerID INT NOT NULL,
OrderId INT NOT NULL,
ProductId INT NOT NULL,
Quantity INT NOT NULL,
Price DECIMAL(18,3) NOT NULL,
OrderDate datetime NOT NULL DEFAULT GETUTCDATE(),
AreaId INT NOT NULL
)
GO
INSERT INTO dbo.Orders
( CustomerID , OrderId , ProductId , Quantity , Price , OrderDate , AreaId )
VALUES ( 1, 1, 4711, 1, 100.0, GETUTCDATE(), 1 ),
( 2, 2, 4712, 1, 200.0, GETUTCDATE(), 1 ),
( 3, 3, 4713, 1, 500.0, GETUTCDATE(), 2 )
GO
-- Erstelle die Vertriebssteuerungstabelle
CREATE TABLE dbo.SalesPerson
(
SalesPersonLogin NVARCHAR(25) NOT NULL,
SalesAreaId INT NOT NULL
)
GO
INSERT INTO dbo.SalesPerson
( SalesPersonLogin, SalesAreaId )
VALUES ( N'SalesNorth', 1 ),
( N'SalesSouth', 2 )
GO
-- Erstelle nun die 2 Verkäufer (ohne Login weil wir nur testen und keine Active Directory nutzen wollen)
CREATE USER SalesNorth WITHOUT LOGIN
CREATE USER SalesSouth WITHOUT LOGIN
GO
-- Select Rechte werden nun benötigt (beachte, dass wir hier für mehrere Benutzer Rechte gleichzeitig vergeben können)
GRANT SELECT ON dbo.SalesPerson TO SalesNorth, SalesSouth
GRANT SELECT ON dbo.Orders TO SalesNorth, SalesSouth
GO
-- Jetzt fangen wir an unsere Filterfunktion zu bauen. Die Steuerungstabelle gibt schon die Möglichkeit zu filtern
-- Wie immer bei der Entwicklung, bauen wir Stück für Stück in die richtige Richtung
-- Als erstes, mit EXECUTE AS schlüpfen wir in die Rolle des Verkäufers um die Daten so zu filtern wie wir wollen
EXECUTE AS USER= 'SalesNorth'
SELECT USER_NAME() AS WhoAmI,o.* FROM dbo.Orders o
INNER JOIN dbo.SalesPerson sp ON sp.SalesAreaId = o.AreaId WHERE sp.SalesPersonLogin = USER_NAME()
REVERT -- Revert springt zu unserem Sysadmin konto zurück
GO
-- Mit dem zweiten Verkäufer ebenfalls testen
EXECUTE AS USER= 'SalesSouth'
SELECT USER_NAME() AS WhoAmI,o.* FROM dbo.Orders o
INNER JOIN dbo.SalesPerson sp ON sp.SalesAreaId = o.AreaId WHERE sp.SalesPersonLogin = USER_NAME()
REVERT
GO
-- Nun wissen wir, dass wir eine richtig funktionierende Filterung haben.
-- Jetzt wollen wir die Daten permanent filtern, ohne ein JOIN nutzen zu müssen.
-- Dazu erstellen wir eine Funktion um die Filterlogik einzurichten.
CREATE FUNCTION dbo.SalesAreaFilter ( @AreaId AS INT )
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
SELECT 1 AS rowLevelPredicateResult
FROM dbo.SalesPerson sp
WHERE sp.SalesAreaId = @AreaId
AND sp.SalesPersonLogin = USER_NAME();
GO
-- Zum Abschluss muss ein Policy erstellt werden.
-- Der Policy wendet die zuvor erstellte Funktion auf eine Tabelle an
CREATE SECURITY POLICY OrdersFilter
ADD FILTER PREDICATE dbo.SalesAreaFilter(AreaId)
ON dbo.Orders
WITH (STATE = ON);
GO
-- Nun schlüpfen wir wieder in die Rolle des Verkäufers um zu sehen
-- ob die Daten nun auch beim einfachen SELECT gefiltert werden
EXECUTE AS USER= 'SalesNorth'
SELECT USER_NAME() AS WhoAmI,o.* FROM dbo.Orders o
REVERT
GO
-- Mit dem zweiten Verkäufer ebenfalls testen
EXECUTE AS USER= 'SalesSouth'
SELECT USER_NAME() AS WhoAmI,o.* FROM dbo.Orders o
REVERT
GO
-- ERFOLG!!
-- Allerdings müssen wir wieder aufpassen.
-- Als erste Nebeneffekt, werden Orders auch für uns als Sysadmin gefiltert
SELECT USER_NAME() AS WhoAmI
SELECT USER_NAME() AS WhoAmI,o.* FROM dbo.Orders o
GO
-- Das kann eine gewollte Situation sein. Als Sysadmin sind wir für den
-- Datenbankserverbetrieb zuständig, nicht aber die Verkäufe
-- Falls wir dennoch Zugriff auf die Rohdaten benötigen, müssen wir die Filterfunktion
-- anpassen um unser User immer Zugriff zu gewähren
-- Alles wegschmeißen und mit Sysadmin Ausnahme wieder aufbauen
DROP SECURITY POLICY IF EXISTS dbo.OrdersFilter
DROP FUNCTION IF EXISTS dbo.SalesAreaFilter
GO
CREATE FUNCTION dbo.SalesAreaFilter ( @AreaId AS INT )
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
SELECT 1 AS rowLevelPredicateResult
FROM dbo.SalesPerson sp
WHERE USER_NAME() = 'dbo' -- GOD MODE
OR ( sp.SalesAreaId = @AreaId
AND sp.SalesPersonLogin = USER_NAME()
);
GO
CREATE SECURITY POLICY OrdersFilter
ADD FILTER PREDICATE dbo.SalesAreaFilter(AreaId)
ON dbo.Orders
WITH (STATE = ON);
GO
-- Ein letztes Mal alles testen
EXECUTE AS USER= 'SalesNorth'
SELECT USER_NAME() AS WhoAmI,o.* FROM dbo.Orders o
REVERT
GO
-- Mit dem zweiten Verkäufer ebenfalls testen
EXECUTE AS USER= 'SalesSouth'
SELECT USER_NAME() AS WhoAmI,o.* FROM dbo.Orders o
REVERT
GO
-- Nun sehen wir als Sysadmin wieder alles :)
SELECT USER_NAME() AS WhoAmI,o.* FROM dbo.Orders o
GO
USE tempdb
GO
-- Aufräumen
DROP TABLE IF EXISTS dbo.MaskedTable;
DROP USER IF EXISTS ZeroCool
GO
-- Man achte auf die zusätzlichen Angaben "MASKED WITH....."
-- So können die Verschleierungsoptionen gesteuert werden.
CREATE TABLE dbo.MaskedTable
(
Col1 INT NOT NULL PRIMARY KEY CLUSTERED,
Col2 VARCHAR(255) MASKED WITH (FUNCTION = 'default()'),
Col3 VARCHAR(255) MASKED WITH (FUNCTION = 'email()'),
Col4 INT MASKED WITH (FUNCTION = 'default()'),
Col5 VARCHAR(255) MASKED WITH (FUNCTION = 'partial(5,"XXXXXXX",0)')
);
GO
INSERT INTO dbo.MaskedTable
( Col1, Col2, Col3, Col4, Col5 )
VALUES ( 1, 'Testdata for DDM', 'Test@Test.com', 100, 'More test data' ),
( 2, 'Mess with the best, die like the rest', 'zerocool@acidburn.com' , 200 , 'pool on the roof must have a leak' )
-- Als Sysadmin *und* Tabellenersteller, dürfen wir alle Daten sehen
SELECT USER_NAME() AS WhoAmI,*
FROM dbo.MaskedTable
GO
-- Testuser erstellen
CREATE USER ZeroCool WITHOUT LOGIN
GO
-- SELECT auf die Testtabelle zulassen
GRANT SELECT ON dbo.MaskedTable TO ZeroCool
GO
-- Tabelle als Testuser abfragen, wir sollten verschleierte Daten sehen
EXECUTE AS USER = 'ZeroCool'
SELECT USER_NAME() AS WhoAmI,
Col1, -- int
Col2, -- varchar + default()
Col3, -- varchar + email()
Col4, -- int + default()
Col5 -- varchar + partial(5,"XXXXXXX",0)
FROM dbo.MaskedTable
REVERT
-- Nun unser Testuser das Recht geben verschleierte Daten zu sehen
GRANT UNMASK TO ZeroCool -- << UNMASK wird auf Datenbankebene gesetzt und (noch) nicht auf Tabelle oder Spaltenebene
GO
-- Jetzt sind die Daten sichtbar
EXECUTE AS USER = 'ZeroCool'
SELECT USER_NAME() AS WhoAmI,* FROM MaskedTable
REVERT
GO
-- Und jetzt nehmen wir das Recht wieder weg
REVOKE UNMASK TO ZeroCool
GO
-- Können wir die Daten auch ohne Rechte einsehen?
EXECUTE AS USER = 'ZeroCool'
SELECT USER_NAME() AS WhoAmI,
CAST(Col2 AS int) -- Col2 ist kein INT, ein CAST wird fehlschlagen. Beim Beta-Release wurden die Daten unverschleiert als Fehler ausgegeben
FROM dbo.MaskedTable
REVERT
-- Wie ist es wenn wir die Daten in eine andere Tabelle "exportieren"?
EXECUTE AS USER = 'ZeroCool'
SELECT USER_NAME() AS WhoAmI,
Col1,
Col2,
Col3,
Col4,
Col5
INTO dbo.MaskedTableDump
FROM dbo.MaskedTable
-- Hmmm, wir dürfen in ein Userdatenbank keine Tabelle anlegen :(
SELECT USER_NAME() AS WhoAmI,
Col1,
Col2,
Col3,
Col4,
Col5
INTO #MaskedTableDump -- Aber Jeder darf Temp-Tabellen in tempdb erstellen!!! :)
FROM dbo.MaskedTable
-- Jetzt die Temp-Tabelle auslesen. (Bei Release Candidate 2 wurde dieses Schlüpfloch geschlossen)
SELECT * FROM #MaskedTableDump
-- Wenn wir wissen welche Datentypen die Tabelle hat, können wir aber mit Systemfunktionen teilweise
-- an die Daten kommen. Dynamic Data Masking ist also (noch) nicht perfekt!
-- Col4
SELECT USER_NAME() AS WhoAmI,
SQRT(SQUARE(Col4)), -- SQRT(SQUARE()) liefert die richtigen Daten
EXP(LOG(Col4)), -- EXP(LOG()) liefert (fast) die richtigen Daten
Col4 -- Col4 wird noch als 0 (also maskiert) dargestellt
FROM dbo.MaskedTable
REVERT
GO