DDM – rozszerzenie tematu
O technologii Dynamic Data Masking pisałem dwukrotnie w 2025 roku, aby przybliżyć jej działanie użytkownikom baz danych Progress OpenEdge od wersji 12.8. W poprzednich artykułach skupiłem się głównie na podstawach: omówiłem sposób aktywacji mechanizmu DDM w bazie danych oraz konfigurację czterech dostępnych typów masek dla wybranych pól i tabel.
Dynamic Data Masking jest jednak rozwiązaniem, które poza samą konfiguracją wymaga również dobrego zrozumienia sposobu działania mechanizmu maskowania, jego wpływu na aplikacje oraz pewnych ograniczeń. W praktyce oznacza to, że wdrożenie DDM nie sprowadza się wyłącznie do zdefiniowania reguł maskowania, ale powinno być poprzedzone analizą wymagań bezpieczeństwa, zgodności oraz wpływu na istniejące reguły biznesowe.
W tym artykule chciałbym więc spojrzeć na tę technologię z bardziej praktycznej i technicznej perspektywy. Pokażę nie tylko zalety wynikające z zastosowania Dynamic Data Masking, ale również ograniczenia i potencjalne problemy, które mogą pojawić się podczas wdrożenia. Odniosę się także do kilku nieporozumień dotyczących działania DDM, które pojawiały się w pytaniach i dyskusjach po publikacji wcześniejszych materiałów.
Jednym z pytań było: co się stanie jeśli pole typu INTEGER będzie przesłane do obiektu, jako wartość wymagana, a administrator nałoży na nie maskę PARTIAL. Otóż należy pamiętać, że dla każdego rodzaju maski obowiązuje zasada zgodności typów. Spróbujmy zastosować taką maskę na pole Balance (DECIMAL). Postępujemy dokładnie tak jak w poprzednich artykułach, a na koniec nakładamy maskę:
USING OpenEdge.DataAdmin.DataAdminService FROM PROPATH.
DEFINE VARIABLE service AS DataAdminService NO-UNDO.
DEFINE VARIABLE lResult AS LOGICAL NO-UNDO.
service = NEW DataAdminService(LDBNAME("DICTDB")).
lResult = service:setDDMConfig("Customer","Balance","P:2,*","#DDM_SEE_ContactInfo").
Dostajemy komunikat o błędzie wynikający z konfliktu pola liczbowego z maską znakową.

Przejdę teraz do ważniejszej kwestii związanej z DDM, ale najpierw zdefiniuję maskę domyślną dla pola Balance.
USING OpenEdge.DataAdmin.DataAdminService FROM PROPATH.
DEFINE VARIABLE service AS DataAdminService NO-UNDO.
DEFINE VARIABLE lResult AS LOGICAL NO-UNDO.
service = NEW DataAdminService(LDBNAME("DICTDB")).
lResult = service:setDDMConfig("Customer","Balance","D:","#DDM_SEE_ContactInfo").
Startuję dwie sesje w edytorze procedur, logując się do bazy jako Admin i jako User. Uruchamiam prosty program wyświetlający wartość pola Balance dla pierwszego rekordu Customer. Zgodnie z przewidywaniem dla Admina jest to prawdziwa wartość (z lewej), a dla Usera wartość zamaskowana, czyli zero (z prawej).

Podstawowe pytanie brzmi: na jakim poziomie odbywa się maskowanie danych? Czy na warstwie prezentacji czy dostępu do danych? Jest to kwestia zasadnicza, ale zanim to wyjaśnimy uruchomię jeszcze jeden prosty przykład. Dodałem do tablicy Customer pole znakowe cStatus. W zależności od wartości pola Balance ustawiany jest status klienta. Jeśli jego Balance, czyli “saldo” wynosi zero to status zmienia się na “Blocked”.
Pole Balance nie jest tutaj wyświetlane. Uruchamiam program ponownie jako Admin…

… i jako User.

Widzimy, że chociaż wartość pola Balance jest niezerowa, to logika aplikacji w drugim oknie widzi ją jako właśnie zerową. Ten przykład pokazuje najważniejszy problem związany z Dynamic Data Masking — mechanizm maskowania może wpływać nie tylko na prezentację danych, ale również na działanie logiki biznesowej. Zresztą, nie ma co się dziwić. Gdyby maskowanie dotyczyło tylko wyświetlania danych wystarczyłoby przypisać pole do zmiennej i je wyświetlić.
A zatem w wielu przypadkach aplikacja otrzymuje już zamaskowaną wartość podczas odczytu danych z bazy. Oznacza to, że warunki biznesowe, walidacje czy obliczenia mogą działać na danych zmodyfikowanych przez mechanizm DDM. Dlatego maskowanie danych nie powinno być traktowane jako element logiki aplikacyjnej.
Najbezpieczniejszym podejściem jest rozdzielenie warstw odpowiedzialności:
– logika biznesowa powinna operować na rzeczywistych danych,
– maskowanie powinno być stosowane na etapie prezentacji danych użytkownikowi,
– mechanizm DDM warto wykorzystywać głównie dla raportowania, odczytu danych oraz ograniczania dostępu do danych poufnych dla użytkowników biznesowych, audytorów czy pracowników wsparcia technicznego.
Rozważmy kolejny przypadek.

Admin uruchamia zapytanie dla 5 pierwszych rekordów Customer. Widać, że dwa z nich mają wartość pola Balance powyżej 1000.
A teraz uruchamiam poniższy program jako User.

Nie powinno nas dziwić, że licznik cnt wynosi zero ponieważ wartości pola Blanace są dla Usera zamaskowane i program widzi same zera.
Ale co się dzieje w poniższym przykładzie?

Zmieniliśmy nieco logikę przesuwając warunek na pole Balance do otwarcia pętli (fraza WHERE) i licznik wychwytuje teraz te dwie wartości > 1000.
Możecie sprawdzić sami, że jeśli wyświetlilibyśmy teraz to pole w pętli to nadal byłoby zamaskowane.
Dlaczego tak się dzieje? Otóż tutaj filtrowanie jest wykonywane bezpośrednio przez silnik bazy danych przed zastosowaniem maskowania. Oznacza to, że rekord może zostać wybrany na podstawie rzeczywistej wartości Balance, mimo że użytkownik po odczycie nadal zobaczy wartość 0. I choć maskowanie nie pozwoli nam na poejrzenie wartości możemy dostać pewną informację na temat ilości klientów których saldo jest większe od określonej wartości. Jeśli zbiór danych nie jest duży to dość łatwo możemy zawęzić zakres wartości pola Balance dla poszczególnych klientów.
Samo maskowanie wartości często nie wystarcza, ponieważ liczba rekordów, wyniki agregacji czy czas wykonania zapytania również mogą ujawniać informacje o danych.
W praktyce oznacza to, że mechanizm DDM musi być projektowany razem z logiką aplikacji, a nie traktowany jako niezależna warstwa bezpieczeństwa.
Na zakończenie: nie tylko OpenEdge
Warto podkreślić, że opisane ograniczenia nie są specyficzne wyłącznie dla Dynamic Data Masking w Progress OpenEdge. Podobne ograniczenia mają również inne technologie tego typu dostępne na rynku.
To nie jest więc „bug” konkretnego rozwiązania, ale raczej naturalna cecha samego podejścia do maskowania danych. DDM ukrywa wartości pól, ale nie zawsze ukrywa informacje wynikające z działania aplikacji, zapytań czy agregacji.
Dlatego nawet jeśli użytkownik nie widzi danych bezpośrednio, nadal może czasem wyciągać pewne wnioski na podstawie:
– liczby rekordów,
– działania warunków,
– agregacji,
– sortowania,
itp.
W praktyce oznacza to, że Dynamic Data Masking warto traktować jako dodatkową warstwę ochrony danych, a nie jedyne zabezpieczenie systemu.











































