[Uwaga] Ten artykuł został pierwotnie przygotowany w języku angielskim i został przetłumaczony na język polski.
Niedawno, podczas jednego z moich projektów, musiałem przyznać dostęp do bazy danych konkretnym użytkownikom. Klient chciał, aby widzieli oni wszystkie tabele, ale z wyłączeniem niektórych kolumn zawierających dane wrażliwe, takie jak wynagrodzenie, dochody, faktury, rozliczenia czy adresy klientów – czyli tak zwane „sensitive data”.
Zdecydowałem się użyć do tego Oracle VPD (Virtual Private Database), ponieważ – zgodnie z dokumentacją Oracle – jeśli korzystasz z Oracle Database XE 21c, VPD jest darmowe (w przypadku innych wersji radzę sprawdzić to samodzielnie). W tym artykule pokażę Ci, jak wykorzystać to rozwiązanie do maskowania danych, czyli ukrywania ich przed użytkownikami bazy danych Oracle, a jako bonus – również przed użytkownikami Oracle APEX.
Oto rzeczy, których będziesz potrzebować, aby odtworzyć przykład pokazany w tym artykule:
Zanim zrobię cokolwiek innego, muszę przyznać użytkownikowi dostęp do tabeli. W moim przypadku użytkownik nazywa się TEST, więc polecenie wygląda następująco:
--connect as HR GRANT SELECT ON EMPLOYEES TO TEST;
Wynik wygląda tak:
Jednak, jak wspomniałem wcześniej, nie chcę, aby użytkownik TEST widział dane z kolumny SALARY. Jak to zrobić? Musisz wykonać kilka prostych kroków.
Pierwszą rzeczą jest stworzenie funkcji, która obsłuży polityki VPD. Musi ona zostać utworzona na schemacie, do którego użytkownik TEST nie ma dostępu (ja używam ADMIN dla Oracle Cloud).
--connect as ADMIN (używam Oracle Cloud)
create or replace function f_vpd_column_masking(
p_schema varchar2,
p_obj varchar2
) return varchar2 as
l_database_user varchar2(255) DEFAULT USER;
l_predicate varchar2(100);
begin
if l_database_user in ('TEST') then
l_predicate := '1=2';
end if;
return l_predicate;
end f_vpd_column_masking;
Następnie musisz utworzyć politykę VPD, która pozwoli na ukrycie danych.
--execute as ADMIN
begin
dbms_rls.add_policy
(object_schema => 'HR',
object_name => 'EMPLOYEES',
policy_name => 'EMPLOYEES_SELECT',
function_schema => 'ADMIN',
policy_function => 'f_vpd_column_masking',
statement_types => 'SELECT',
sec_relevant_cols => 'SALARY',
sec_relevant_cols_opt => dbms_rls.ALL_ROWS);
end;
/
--clean up
--EXEC DBMS_RLS.DROP_POLICY('HR','EMPLOYEES','EMPLOYEES_SELECT');
Zapobiegnie to wyświetlaniu danych z kolumny HR.EMPLOYEES.SALARY użytkownikom wymienionym w mojej funkcji.
Teraz odpytajmy tabelę EMPLOYEES jeszcze raz (połącz jako TEST).
Wszystko wydaje się działać zgodnie z planem: użytkownik TEST może odpytywać tabelę EMPLOYEES, ale nie widzi żadnych wynagrodzeń.
Warto zauważyć, że zawsze możesz podejrzeć posiadane polityki VPD, używając prostego zapytania poniżej.
--run as ADMIN (SYS) select * from all_policies where object_owner = 'HR';
Ale co, jeśli z jakiegoś powodu chcesz, aby polityka VPD nie wpływała na konkretnych użytkowników? Możesz użyć tego zapytania, aby to osiągnąć.
--run as ADMIN or SYS grant EXEMPT ACCESS POLICY to YOUR_USER;
Jeden z moich kolegów zapytał mnie, jak chronić dane przed niektórymi użytkownikami APEX. To całkiem proste – wystarczy zaktualizować funkcję polityki VPD.
--connect as ADMIN (as I'm using Oracle Cloud)
create or replace function f_vpd_column_masking(
p_schema varchar2,
p_obj varchar2
) return varchar2 as
l_database_user varchar2(255) DEFAULT USER;
l_predicate varchar2(100);
begin
if l_database_user in ('TEST') then
l_predicate := '1=2';
end if;
/* dodane, aby chronić przed konkretnymi użytkownikami APEX
Jeśli zalogowany użytkownik APEX to SANDBOX_LTD, zobaczy wartości NULL w kolumnie salary
*/
if SYS_CONTEXT('APEX$SESSION', 'APP_USER') = 'SANDBOX_LTD' then
l_predicate := '1=2';
end if;
/Modyfikuj dowolnie, np. wyklucz tylko użytkowników niemających określonego schematu autoryzacji lub roli./
return l_predicate;
end f_vpd_column_masking;
Teraz użytkownik APEX SANDBOX widzi wszystkie dane w tabeli EMPLOYEES, ale użytkownik SANDBOX_LTD widzi tylko wartości NULL zamiast kwot w kolumnie wynagrodzeń.
Aby pokazać dane wrażliwe użytkownikom APEX z konkretnymi rolami, musisz najpierw stworzyć rolę – na przykład SENSITIVE_DATA – a następnie przypisać ją tylko niektórym użytkownikom.
Następnie będziesz musiał zaktualizować kod funkcji polityki VPD.
--connect as ADMIN (as I'm using Oracle Cloud)
create or replace function f_vpd_column_masking(
p_schema varchar2,
p_obj varchar2
) return varchar2 as
l_database_user varchar2(255) DEFAULT USER;
l_apex_user APEX_WORKSPACE_APEX_USERS.user_name%TYPE;
l_predicate varchar2(100);
l_sensitive_data_access boolean :=false;
begin
--get apex user
l_apex_user := SYS_CONTEXT('APEX$SESSION', 'APP_USER');
--if database user is SANDBOX_LTD or apex user is SANDBOX_LTD then VPD policy hides data
if l_database_user in ('SANDBOX_LTD') or l_apex_user = 'SANDBOX_LTD' then
l_predicate := '1=2';
end if;
--is user not has role SENSITIVE_DATA then data is hidden
l_sensitive_data_access := APEX_ACL.HAS_USER_ROLE (
p_application_id => v('APP_ID'),
p_user_name => l_apex_user,
p_role_static_id => 'SENSITIVE_DATA' );
IF NOT l_sensitive_data_access then
l_predicate := '1=2';
END IF;
return l_predicate;
end f_vpd_column_masking;
I to wszystko. Jak widzisz, ukrywanie konkretnych danych przed użytkownikami Oracle DB lub Oracle APEX jest całkiem proste – wystarczy kilka prostych zapytań, aby wykonać zadanie. Jeśli chcesz dowiedzieć się więcej o VPD lub wdrożyć bardziej skomplikowane polityki, sprawdź tę dokumentację dotyczącą kontroli dostępu do danych od Oracle. Jeśli masz jakieś pytania, skontaktuj się ze mną pod adresem rgrzegorczyk@pretius.com. Możesz również sprawdzić moje inne artykuły na blogu Pretius: