Novinka, tentokrát z pohledu bezpečnosti (Oracle Advanced Security Guide). Od Oracle 12c je tu Oracle Data Redaction, něco co bychom v češtině mohli nazvat maskováním. Hodnoty, které vrátí select lze změnit například na hvězdičky nebo třebas nezobrazit poslední 4 čísla u rodného čísla. Data Redaction Policy se aplikuje online při dotazování a k dispozici je i možnost filtrovat na základě SYS_CONTEXT hodnot. K tomu všemu slouží nový package DBMS_REDACT.
Existuje celkem 5 různých variant:
- FULL REDACTION – všechno je maskováno
- PARTIAL REDACTION – je maskována pouze část hodnoty sloupce (poslední 4 čísla apod.)
- REGULAR EXPRESSION - jsou maskovány hodnoty odpovídající regulérnímu výrazu (možné pouze pro text)
- RANDOM REDACTION – náhodně generované hodnoty (tzn. při každém spuštění jiné)
- NO REDACTION – bez maskování, určeno pro testování apod.
A z manuálu pak pár důležitých poznámek:
- V balíku DBMS_REDACT jsou k dispozici předefinované typy pro maskování některých hodnot. Pochopitelně americké standardy/formáty čísel (security number, zip code apod.)
- Data Redaction Policy přeplácne právo EXEMPT REDACTION POLICY, podobně jako je právo EXEMPT ACCESS POLICY pro potlačení VPD
- Na jednom sloupci může existovat pouze jedna policy
Fajn a hurá do hébičkování, první a nejjednodušší možnost – FULL REDACTION. Nejprve však nějaká tabulka na zkoušku:
CREATE TABLE TEST_REDACTION AS
SELECT ROWNUM AS ID,
DECODE(ROWNUM,1,'Suicide Silence',2,'Beneath the Sky',3,'Bleed From Within') AS BAND,
ROWNUM*MOD(ROWNUM,2)*1000 AS COST
FROM DUAL CONNECT BY LEVEL<5;

Tabulka pro zkoušení data redaction
A rovnou na to pověsme Data Redaction Policy:
BEGIN
DBMS_REDACT.ADD_POLICY (
object_schema=>'AZOR',
object_name=>'TEST_REDACTION',
policy_name=>'REDACTION_POLICY_2',
column_name=>'BAND',
function_type=>DBMS_REDACT.FULL,
expression=>'1=1',
enable=>TRUE,
policy_description=>'First test Data Redaction',
column_description=>'BAND COLUMN');
END;
S tím, že parametry jsou následující:
- object_schema – místo, kde je umístěn objekt, by default null = aktuální schéma
- object_name - jméno tabulku nad kterou chceme data redaction policy navěsit
- policy_name - jméno data redaction policy
- column_name – název sloupce, pro který bude tato funkce aplikována
- fuction_type – typ data redaction policy – NONE, FULL, PARTIAL, RANDOM, REGEXP
- expression - výraz/filtr pro které řádky se má funkce aplikovat – 1=1 je pro všechny, může však být něco složitějšího, včetně odkaz na SYS_CONTEXT
- enable - aktivní/neaktivní, by default data redaction policy je zapnutá
- policy_description,column_description – prostě popis pro dokumentaci a tak.
Podívejme se jak vypadá select z tabulky po přidání Oracle Data Redaction:

Data Redaction - příklad 1
Výborný, hodnoty byly vymaskovány, done. Původně jsem zde chtěl zkusit všechny typy Oracle Data Redaction, ale to asi není tak zajímavé, jako když sejdu z cesty a povedu tento příspěvek jinou cestou. Pochopitelně mi zajímalo jak je to s vymaskovanými hodnoty a s joiny, where apod. Takže jsem zkusil následující:

Oracle Data Redaction vs. where podmínka
Tzn, když se odkážeme na konkrétní hodnotu ve sloupci, můžeme podle ní filtrovat. Což je na jednu stranu fajn, na stranu druhou, ale v tomhle konkrétním případě dokážu zjistit jaká hodnota ve sloupci je, použiji-li hrubou sílu. Takže pojďme raději zkoumat tohle
Insertněme nějaký řádek do tabulky a naší snahou pak bude zjistit hodnotu ve sloupci BAND:
INSERT INTO TEST_REDACTION VALUES(5,
CHR(DBMS_RANDOM.VALUE(65,90)) ||
CHR(DBMS_RANDOM.VALUE(65,90)) ||
CHR(DBMS_RANDOM.VALUE(65,90)) ||
CHR(DBMS_RANDOM.VALUE(65,90)) ||
CHR(DBMS_RANDOM.VALUE(65,90))
,99);
commit;
CHR(DBMS_RANDOM.VALUE(65,90)) – náhodné číslo od 65 do 90 (čísla ASCII pro velká písmena) a z toho CHR a to všechno 5x za sebou – tedy ve sloupci BAND je 5 náhodných velkých písmen. ID řádku je 5 a sloupec COST má hodnotu 99. Sloupec COST doufám, že nemate, chtěl jsem ho pojmenovat jako případně sloupec, který by jménem mohl být kandidátem pro maskování a jako jelito mi nenapadlo, že by se to mohlo pléct s COSTem optimalizátoru se kterým to nesouvisí, což je doufám vidět.
Takže select tohoto řádku:

Oracle Data Redaction - zjištění hodnoty
Ok, řekněme, že máme zjistit hodnotu nějakého sloupce po aplikaci této redakční politiky – a předpokládejme že nás bude zajímat nějaký konkrétní řádek a ROWID bude nezbytné pro ověření, že ještě nečelíme nějakému VPD či nastavení náhodného maskování. A nyní jak na to!
Je k dispozici možnost ptát se na sloupec BAND v klauzuli WHERE. Velká písmena, která jsou ve sloupci jsou na hodnotách ASCII 65 až 90, tedy když rozpůlíme interval možných hodnot :(65+90)/2 je cca 78, což je dle ASCII písmeno ‘N’, tedy půlka abecedy. A nyní zjistíme jestli hodnota ve sloupci BAND je větší nebo menší než N, tedy jestli hodnota ve sloupci BAND začíná na A-M nebo na O-Z:

Oracle Data Redaction - získání hodnot I
Jinými slovy: první písmeno je něco mezi A-M. Nyní by chtělo interval rozpůlit znovu (65+78)/2 cca 72, což je písmeno H a opět spustit select a zjisti pro který z intervalů A-H či H-M nám databáze vrátí řádek. Pokud si to zkusím, tak to vrací řádek pro menší než <’H’, tedy v první písmeno je něco mezi A-H a takhle bychom mohli pokračovat. Nebo se na to vykašlat a napsat na to script:
DECLARE
lb_found BOOLEAN:=FALSE;
ln_fetch NUMBER;
lc_actual_predicate VARCHAR2(5);
lc_prediacate VARCHAR2(5);
BEGIN
FOR I_OVER_LETTERS IN 1..5 LOOP
FOR J_OVER_ASCII_VALUES IN 65..90 LOOP
select count(1) into ln_fetch from azor.TEST_REDACTION
where rowid='AAAXH2AAGAAAA22AAA' and
band>=lc_actual_predicate ||chr(J_OVER_ASCII_VALUES);
lc_prediacate:=chr(J_OVER_ASCII_VALUES-1);
EXIT WHEN ln_fetch=0;
END LOOP;
lc_actual_predicate:=lc_actual_predicate|| lc_prediacate;
DBMS_OUTPUT.PUT_LINE(lc_actual_predicate);
END LOOP;
END;
Jehož výstupem je u mě slovo ‘DORSE’. Samozřejmě se jedná o hodně hloupě napsaný script, který nedělá ani binární půlení a který počítá s tím, že ve sloupci jsou opravdu jen velká písmena a je jich 5. Na stranu druhou, modifikace a vylepšení a zobecnění je jednoduché. So:

Oracle Data Redaction - získání hodnot II
Výborný, nyní pojďme pro mé účty nagrantovat EXEMPT REDACTION POLICY, což nás zbaví Oracle Data Redaction:
grant EXEMPT REDACTION POLICY to AZOR,AZOR3;
A podívejme se, co je opravdu v tabulce:

Oracle Data Redaction - získání hodnot III
Takže asi tolik k defaultnímu nastavení DMBS_REDACTION.FULL. K ostatním nastavením se snad na blogu ještě dostanu, speciálně nastavení s regulérními výrazy je vcelku zajímavé.
K novému package patří také nová VIEW, kde je možné si Oracle Data Redaction politiku prohlédnout:
- REDACTION_POLICIES – obecně politika nad tabulkami
- REDACTION_COLUMNS – konkrétní politika nad sloupci
- REDACTION_VALUES_FOR_TYPE_FULL – defalutní hodnoty pro FULL maskování, VARCHAR2 se maskuje jako NULL, NUMBER jako 0 atd.