Maskarada dla danych – Dynamic Data Masking – SQL Server Security

Dotychczas (przed SQL Server, 2016) jeśli posiadaliśmy tabele, w których wybrane kolumny były przeznaczone tylko dla niektórych użytkowników mieliśmy, co najmniej 3 opcje:

  • Nadać odpowiednie uprawnienia dla tych osób jednocześnie odebrać pozostałym. Czyli w myśl zasady wszystko albo nic,
  • Przykryć tabele widokiem umożliwiając odczyt danych z kolumn mniej wrażliwych dla osób nieupoważnionych. Można to uznać za uzupełnienie ww. punktu.
  • Wykorzystać metodę szyfrowania danych, np. Cell-Level Encryption

Jednak wraz z wersja SQL Server 2016 mamy do dyspozycji dodatkową funkcjonalność, która może spełniać takie wymaganie biznesowe. Mowa tutaj o Dynamic Data Masking.

Czym jest Dynamic Data Masking?

W wolnym tłumaczeniu, dynamicznym maskowaniem danych. Konkretnie Dynamic Data Masking ma na celu zapobieganie dostępu do poufnych danych poprzez zaciemnianie/zakrywanie wrażliwych danych użytkownikom, którzy nie powinni mieć dostępu do tych danych. 

Zalety Dynamic Data Masking

Najlepsze rozwiązanie to takie, które nie wymagają dużej ilości zmian. To największą zaletą dynamicznego maskowanie danych. Implementacja jest możliwa bez modyfikowania istniejących zapytań. Wiąże się to z zdefiniowaniem funkcji maskujących na wybranych kolumn w tabelach. Takie zmiany są transparentne dla aplikacji. Natomiast samo przyznanie możliwości odczytu od maskowanych danych odbywa się poprzez nadanie uprawnień bezpośrednio użytkownikom lub rolą.

Ograniczenia Dynamic Data Masking

Jak każde rozwiązanie i to ma swoje wady i ograniczenia. Mianowicie nie można definiować funkcji maskujących dla kolumn w następujących przypadkach:

  • gdy stosujemy dla wybranej kolumny Always Encrypted (również funkcja dodana w SQL Server 2016),
  • gdy używamy FILESTREAM,
  • dla kolumn wyliczeniowych,

Dodatkowo innym ograniczeniem jest, że kolumna z maskowaniem danych nie może być kluczem dla indeksu FULLTEXT. W kwestii wad, brak na tą chwilę możliwości selektywnego nadawania uprawnień. Uprawnienia nadaję się na poziomie bazy danych, niestety nie dla określonej tabeli lub kolumny. Słabo.

Funkcje maskujące

Poniżej przykład implementacji Dynamic Data Masking na prostym przykładzie aby móc zobaczyć efekt zaciemniania w zależności od typu danych oraz wybranej funkcji maskującej.

Funkcja domyślna default() realizuję pełne maskowanie w zależności od typu danych danej kolumny.

Kolejna funkcją jest email() która ujawnia pierwszą litere adresu oraz sufiks w postacie nazwy domeny najwyższego poziomu.

Funkcje random([start range], [end range]) może być użyta na dowolnym typie liczbowym w celu zamaskowania oryginalnej wartości losową wartością z określonego zakresu.

Ostatnia funkcja to partial(prefix,[padding],suffix)?), która umożliwia samodzielne ustalenie reguły maskowania. Ustalamy ilość ujawnianych znaków na początku i końcu oraz niestandardowe popełnienie w środku.

Dynamic Data Masking i uprawnienia

Użytkownikom którzy mają uprawnienia do odczytu dane będą się wyświetlać zgodnie z użytą funkcją maskującą. Aby umożliwić wyświetlanie wrażliwych danych osobą którzy są do tego upoważnieni musimy nadać  uprawnienie UNMASKTak jak pisałem w punkcie wad Dynamic Data Masking, uprawnienie te jest na poziomie bazy danych. Czyli niestety wszystko albo nic.

Poza tym, użytkownicy z rolami db_owner automatycznie posiadają uprawnienia UNMASK. Również warto wspomnieć, że Dynamic Data Masking nie zapobiega wykonywania instrukcji DML przez użytkowników, którzy mają do tego uprawnienia. Wykonanie UPDATE będzie bez problemowe dla osoby, która posiada do tego uprawnienia mimo braku GRANT UNMASK. Warto o tym pamiętać.

Wydajność

Wpływ Dynamic Data Masking na wydajność ma być marginalny. Moje testy również na to wskazywały. Poniżej jeden z nich, wykonany na bazie AdventureWorks2016CTP3.

Wynik dla tego zapytań, przed implementacją Dynamic Data Masking, po implementacji funkcji maskujących dla użytkownika z uprawnieniami UNMASK oraz użytkownika bez takich uprawnień.

bez DDM DDM/USER z uprawnieniami DDM/USER bez uprawnień
CPU [ms] TIME [ms] CPU [ms] TIME [ms] CPU [ms] TIME [ms]
1 156 777 187 709 175 845
2 140 675 234 780 156 813
3 187 766 188 715 219 679
4 172 823 157 772 156 686
5 152 772 172 940 172 852
6 172 725 156 850 203 752
AVG 163 756 182 794 180 771

Różnicę są bardzo małe, jednak implementacja tego lub każdego innego rozwiązania nie wyobrażam sobie bez wcześniejszych testów w celu faktycznego wpływu rozwiązania na naszą aplikacje.

Poniżej jeszcze szybkie porównanie planów zapytań, gdzie zwrócić można uwagę na dwa elementy. Nieznaczną różnice między kosztem (3.07304 vs 3.07892) oraz pojawienie się operatora Compute Scalar, który oznacza w tym przypadku wykonanie funkcji maskującej.

Dynamic Data Masking - compare plan

Szczegółowy plan dla zapytania przed implementacją maskowania danych.

query plan - compute scalar

Szczegółowy plan dla zapytania po implementacji Dynamic Data Masking.

Dynamic Data Masking - query plan - compute scalar

Podsumowanie

Dynamic Data Masking nie jest rozwiązaniem idealnym, ma swoje zalety takie jak łatwość implementacji jak i wady w postacie uprawnień na zasadzie zero-jeden. Jednak jest to kolejne rozwiązanie, które dostarcza nam SQL Server w celu łatwiejszego i kompleksowego zapewniania bezpieczeństwa danych w naszych firmach. Warto o nim pamiętać. W kolejnym wpisie pokażę, w jakim scenariuszu maskowanie danych może się idealnie sprawdzić.

Z pasją poświęcam czas na zdobywanie wiedzy w zakresie szeroko rozumianej Data Platform. Zachwycony językiem skryptowym Windows PowerShell. Swoją wiedzę, doświadczenia i spostrzeżenia opisuję na blogu.

Leave a Reply

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *