PostgreSQL9.5新特性之行级安全性及其应用级解决方案

1.行级安全性策略

Postgresql在9.5版本中,新增了行级安全性特性(RLS),该特性在数据安全体系提供了在传统的授权安全体系之外更细粒度的控制。对应的,Oracle在很久之前提供了类似的VPD(Virtual Private Database)技术,该技术在Oracle10g时代就已经成熟。在sql Server 2016中,也提供了类似的行级安全特性。如今Postgresql在本次发布的大版本中也提供了该新特性,本文将对该技术做详细地介绍,然后提出对应的应用级解决方案。

1.1.行级安全策略概述

在之前版本的数据安全技术中,是通过GRANT/REVOKE指令实现的,这两个指令提供了对象级的安全限制,针对表,还提供了列级的安全限制。但是很多场景中,往往希望不同的用户访问同一个表能看到不同的数据,也就是行级安全的需求,这个特性在9.5中提供了支持。该版本中,在正常的SQL查询和数据更新之外,可以附加额外的行级安全策略,可以限制查询返回以及数据操作的结果。认的话,表没有任何安全策略限制。 所有对数据的操作,包括数据查询和数据更新,都受到策略的限制,如果没有配置安全策略,所有的数据查询和更新都会禁止,但是对全表进行操作的命令,比如TruncATE和REFERENCES不受影响。 行级安全策略可以加在命令上,也可以加在角色上,也可以两者都加。命令可以是ALL,SELECT,INSERT,UPDATE和DELETE,同一个策略也可以赋予多个角色。但是表的所有者,超级用户(postgres)以及加上了BYPASSRLS属性的角色不受安全性的限制。如果应用想忽略行级安全性机制的限制,也可以将row_security设置为off。 启用行级安全的表如何对数据的查询和更新进行控制呢?这是通过一个返回布尔值的表达式实现的。这个表达式优先于查询条件和查询内的函数,这个规则唯一的例外是leakproof函数。这里需要两个表达式,分别对数据的查询和更新进行独立地控制。 只有所有者才具有启用/禁用行级安全性,给表添加策略的权限。 CREATE POLICY,ALTER POLICY,DROP POLICY命令分别用于策略的创建、修改删除ALTER TABLE可以用于行级安全性的启用/禁用。 每个策略都有一个名字,每个表可以定义多个策略,因为策略是针对表的,所以表内的多个策略名字必须唯一,但是不同的表可以有同名的策略,当表有多个策略时,多个策略之间是OR的关系。

1.2.相关示例

1.2.1.启用行级安全性

要开启表的行级安全性,需要使用ALTER TABLE命令,如下:

CREATE TABLE user (id text,name text,email text,manager text);
ALTER TABLE user ENABLE ROW LEVEL Security;

ALTER TABLE也可以用于禁用行级安全性,但是禁用之后并不删除相应的策略。

1.2.2.创建策略

如果希望只有管理者才能看到对应的用户

CREATE POLICY user_manager ON user TO managers USING (manager = current_user);

如果未指定角色,那么认为PUBLIC,即针对系统内的所有角色,如果希望系统内每个用户只能看到自己的数据,只需要创建一个下面的简单策略即可:

CREATE POLICY user_policy ON users USING (id = current_user);

如果要限制对数据的更新操作,可以添加WITH CHECK语句,下面的策略允许所有人看到所有的数据,但是只能修改自己的数据:

CREATE POLICY user_policy ON user USING (true) WITH CHECK (id = current_user);

关于创建策略的更详细的说明,可以参照CREATE POLICY命令的手册

2.应用级解决方

从上述可以看出,Postgresql的行级安全性是针对登录数据库的各个具有不同权限的用户的,这对于数据库的设计者来说没有问题,因为他们工作于数据库层。而在实际场景中我们是工作于应用层的,我们希望对应用中的同一条sql语句,能进行不同的权限控制,这里面就涉及三个问题:

  1. 应用是通过一个共享的账户登录数据库的;
  2. 应用的规则可能很复杂;
  3. 可能需要很多的动态参数;

下面就针对上述三个问题,拿出应用级的解决方案。

2.1.三级账户体系

在现实中,应用的开发为了方便,通常的做法是,先用超级用户(postgres)创建一个登录用户角色,然后用新创建的登录用户角色登录,再创建和登录用户名同名的数据库,然后应用也会用这个登录用户连接数据库。 因为行级安全性对于表的所有者以及超级用户等无效,因此原来的开发模型就不再适用,应用就需要通过单独的账户进行登录,这样就形成了三级账户体系:

  1. 超级用户(postgres):作为数据库系统的管理者,拥有整个数据库系统的所有权限;
  2. 数据库所有者:该账户作为数据库的管理者,拥有整个数据库的所有权限;
  3. 应用所有者:该账户认只具有登录数据库的权限,其他的操作都需要相关授权;

应用通过应用所有者账户连接数据库,比如要对某个数据库的public模式内的所有表进行增删改查操作,则需要进行如下的授权: 假定登录用户u1_public

GRANT ALL ON ALL TABLES IN SCHEMA public TO u1_public;

其他对象的权限授权也同理。

2.2.策略函数

不管是USING表达式还是WITH CHECK表达式,都要求表达式的返回值是布尔值,但是对于表达式本身没有限制,因此对于一些复杂的场景,是可以写策略函数的,比如:

ALTER POLICY user_policy ON user USING(policyfunc());

这个是合法的,只要p函数的返回值是布尔就可以。 这个p函数内部显然可以写复杂的逻辑,但是这个p函数暂时看不能传递参数,而且该函数只能返回布尔值也对该函数的发挥空间有了限制,不如Oracle的策略函数返回值是一个字符串的WHERE子句灵活,因为无法用于一些动态场景中。

2.3.动态参数

最后一个问题,就是动态参数,就是具体的策略表达式或者策略函数依赖于应用操作者本身的一些具体的、事务级的参数,比如用户的id,用户所属的组织机构id等,甚至一些用户在界面上进行选择或者输入的数据。这个问题在Oracle中是通过数据库的上下文对象实现的,而在Postgresql中没有这样的对象。那么怎么办呢? Postgresql的强大之处就在这里!这里我们要引入两个概念,一个定制选项一个是系统管理函数中的配置设定函数

2.3.1.定制选项

任何数据库,也包括其他的很多复杂软件,都有很多的配置参数,Postgresql也一样。在Postgresql中,有很多的内置参数,定义在postgresql.conf中,但是在这方面不允许用户随意自定义自己的参数。 我们知道,Postgresql支持扩展,这些扩展可能也需要一些参数,那么在Postgresql中如何定义这些参数呢?他是通过定制选项提供这个功能。 定制选项由两部分组成,首先是扩展名,然后是一个.,然后是属性名,比如rls.userid。因为定制选项可能在扩展还没有加载之前就需要进行设定,因此Postgresql允许这些变量以占位符的形式存在直到扩展模块加载之前都不起任何作用,当扩展模块加载后才会赋予这些变量实际的含义。 了解了这一点,我们发现可以利用这个特性来进行动态参数的传递。 另外要提示一点,在Postgresql9.2版本之前,这个定制选项中的扩展名需要在postgres.conf文件中进行定义,比如custom_variable_classes=rls,而在9.2版本中取消了这一限制,这就给我们提供了更大的方便。

2.3.2.配置设定函数

知道了Postgresql支持动态参数而且知道了动态参数的定义规则之后,下一步就需要知道如何对这些参数进行事务级的赋值/取值了,这时我们就需要利用配置设定函数了。 Postgresql中对于参数的设定,提供了三种方式,一个是SET命令,一个是对于内置参数的ALTER SYstem命令,再一个就是配置设定函数current_setting和set_config,而这两个函数正是我们需要的,我们看下这两个函数的定义:

名称 返回值 描述
current_setting(setting_name) text 获取设定的当前值
set_config(setting_name,new_value,is_local) text 设置参数然后返回新值

这里需要特别关注的就是set_config函数的第三个参数is_local,如果该参数为true,那么该参数只在当前事务有效,如果为false,则对当前会话有效。在SET命令中,也有和这个相对应的LOCAL/SESSION参数。 了解了这两个特性之后,我们就有了对应的应用层解决方案,需要两个步骤:

  1. 定义并传递参数 可以在事务开启之后,进行相应的sql操作之前进行,比如调用如下的sql
SELECT set_config('rls.userid','xiaoming',true);
  1. 策略表达式或者策略函数获取参数 假定对于前述的user表,我们希望应用中登录用户只能查询/更新自己的数据,那么对应的策略如下:
CREATE POLICY user_policy ON user USING (id =current_setting('rls.userid')) WITH CHECK (id=current_setting('rls.userid'));

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


项目需要,有个数据需要导入,拿到手一开始以为是mysql,结果是个PostGreSQL的数据,于是装数据库,但这个也不懂呀,而且本系统用的Oracle,于是得解决迁移转换的问题。 总结下来两个思路。1、PostgresToOracle多金的
本文小编为大家详细介绍“怎么查看PostgreSQL数据库中所有表”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么查看PostgreSQL数据库中所有表”文章能帮助大...
错误现象问题原因这是在远程连接时pg_hba.conf文件没有配置正确。  pg_hba.conf文件在Postgre安装文件目录下的data文件夹中。解决方案1、进入到data目录下,找到pg_hba.conf文件
因本地资源有限,在公共测试环境搭建了PGsql环境,从数据库本地localhost访问正常,在相同网段的远程机器访问报如下错误
wamp 环境 这个提示就是说你的版本低于10了。 先打印php_info(),查看自己的版本(我这边是已经处理后的,之前的忘记截图了)
psycopg2.OperationalError: SSL SYSCALL error: EOF detected 问题提示:exception psycopg2.OperationalError
项目 postgres 连接不上, 所有连接报错 :psql: FATAL: sorry, too many clients already问题原由程序使用连接未及时释放, 连接一直处于 idle 状态处理方式1、 程序里面未释放的连接, 在使用后及时释放
服务器在同一个数据目录上启动了两个PostgreSQL实例(它已经删除postmaster.pid并使用了新的端口号,因此绕过了这种行为的正常保护措施被绕过),导致PostgreSQL的误操作postgresql 报错 FATAL: the database system is
问题原因:数据库崩溃,内存不足造成 或者 数据已损坏,磁盘故障造成首先介绍一下背景,在测试Deepgreen(Greenplum升级版)数据库时,pgbench并发数设置过多,导致数据库卡死了,在进行连接、重启、关闭时,都报同样
第 11 届 PostgreSQL 中国技术大会于 2022 年 1 月 7 日至 9 日在武汉光谷会展酒店成功举办。作为 PostgreSQL 技术领域的年度盛事,postgreSQL 中文社区旨在搭建开放、合作共享的平台,基于开源,创新驱动,共同探讨数据库行业数字化发展方向和未来新机遇。
即将到来的 PostgreSQL 15 已经确认会增加 MERGE 语句,MERGE 可以在单个语句中实现 INSERT、UPDATE 以及 DELETE 操作。在此之前,我们可以使用 INSERT … ON CONFLICT DO …. 语句代替该功能。
本文介绍了PostgreSQL 访问和操作 MySQL 数据库的外部数据包装器:mysql_fdw。mysql_fdw 提供了读写 MySQL 外部表、连接池、WHERE 条件下推、返回字段下推、预编译语句、JOIN 下推、聚合函数(min、max、sum、avg、count)下推、ORDER BY 下推以及 LIMIT OFFSET 下推等功能。
本文给大家分享了一些 PostgreSQL 实用小技巧。
PostgreSQL 全球开发组于 2021-05-20 发布了 PostgreSQL 14 的第一个 beta 版本。本文介绍了该版本中的主要新特性和增强功能,包括性能、新的 multirange 类型、SQL 语句、管理、复制和恢复、安全以及其他方面。
本文介绍了 PostgreSQL 横向子查询(LATERAL)的语法的作用。SELECT 就像一个循环语句,而 LATERAL 就像是一个嵌套循环语句,对于左侧表中的每行记录执行一次子查询操作。
PostgreSQL 15 增加了大量符合 SQL/JSON 标准的函数,使得 JSON 数据的处理更加简单。
PostgreSQL 支持多个不同级别的灵活加密技术,包括密码加密、字段加密、存储加密、传输加密、认证加密以及应用加密,可以保护数据不因数据库服务器被盗、内部管理员或者不安全的网络传输而导致泄露。
目录1.编译incubator-datasketches-cpp编译datasketches-cpp项目编译datasketches-cpp项目的PythonWrapperforDatasketches2.编译incubator-datasketches-postgresql3.Verifyinginstallationofdatasketches-postgresqlwithatestdatabase4.AdvancedExamplesofdata
连接pg需要指定以下的参数:·主机地址·端口·数据库名·用户·密码 如果没有指定上面的参数的话,pg会从环境变量中寻找以下的变量值:·PGHOST或PGHOSTADDR·PGPORT·PGDATABASE·PGUSER·PGPASSWORD 如果只是指定了前面四个参数,pg会尝试寻找口令文件。
pg库也是常用的数据库之一,有些刚开始接触开发的老师可能不熟,这里简单介绍一下,总体使用方法和mysql类似,所以这里只讲配置方法。这个地方test1是数据库1,test2是数据库2,yml文件一定要主要好格式,建议用properties。MyBaitsSqlSessionFactory配置文件。不同数据源的dao层要放到对应文件夹下。TimedConfig配置文件。文件夹格式,这里直接放贴图。Bd3Config配置文件。下面是数据源的配置文件。