写点什么

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

  • 2016-01-18
  • 本文字数:3515 字

    阅读完需:约 12 分钟

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

1. 行级安全性策略

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. 相关示例

启用行级安全性

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

复制代码
CREATE TABLE user (id text, name text, email text,manager text);
ALTER TABLE user ENABLE ROW LEVEL SECURITY;

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

创建策略

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

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(p());这个是合法的,只要 p 函数的返回值是布尔就可以。

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

2.3. 动态参数

最后一个问题,就是动态参数,就是具体的策略表达式或者策略函数依赖于应用操作者本身的一些具体的、事务级的参数,比如用户的 id,用户所属的组织机构 id 等,甚至一些用户在界面上进行选择或者输入的数据。这个问题在 Oracle 中是通过数据库的上下文对象实现的,而在 PostgreSQL 中没有这样的对象。那么怎么办呢?

PostgreSQL 的强大之处就在这里!这里我们要引入两个概念,一个是定制选项,一个是系统管理函数中的配置设定函数

1.定制选项:

任何数据库,也包括其他的很多复杂软件,都有很多的配置参数,PostgreSQL 也一样。在 PostgreSQL 中,有很多的内置参数,定义在 postgresql.conf 中。

我们知道,PostgreSQL 支持扩展,这些扩展可能也需要一些参数,那么在 PostgreSQL 中如何定义这些参数呢?他是通过定制选项提供这个功能。

定制选项由两部分组成,首先是扩展名,然后是一个.,然后是属性名,比如 rls.userid。因为定制选项可能在扩展还没有加载之前就需要进行设定,因此 PostgreSQL 允许这些变量以占位符的形式存在直到扩展模块加载之前都不起任何作用,当扩展模块加载后才会赋予这些变量实际的含义。

了解了这一点,我们发现可以利用这个特性来进行动态参数的传递。

另外要提示一点,在 PostgreSQL9.2 版本之前,这个定制选项中的扩展名需要在 postgres.conf 文件中进行定义,比如 custom_variable_classes=rls,而在 9.2 版本中取消了这一限制,这就给我们提供了更大的方便。

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);
2. 策略表达式或者策略函数中获取参数:假定对于前述的 user 表,我们希望应用中登录的用户只能查询 / 更新自己的数据,那么对应的策略如下:

复制代码
CREATE POLICY user_policy ON user USING (id =current_setting
(<b>'rls.userid'</b><b>)) WITH CHECK (id=current_setting
(</b><b>'rls.userid'</b><b>));</b>

感谢郭蕾对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们,并与我们的编辑和其他读者朋友交流(欢迎加入 InfoQ 读者交流群(已满),InfoQ 读者交流群(#2))。

2016-01-18 17:093391

评论

发布
暂无评论
发现更多内容

谷歌发布 3 款 Gemini 新模型;字节开源 FLUX Dev Hyper SD Lora,8 步生图丨 RTE 开发者日报

声网

Flink优化之--旁路缓存和异步IO

数新网络官方账号

flink

RPA的基本概念:全面解析RPA技术的工作原理和应用场景

八爪鱼采集器︱RPA机器人

RPA 自动化 RPAxAI

易观分析:2024年第2季度中国图书电商市场交易规模达266.2亿元 市场收缩引发行业隐忧

易观分析

MES系统如何帮助企业提高生产效率

万界星空科技

制造业 mes 万界星空科技mes 生产管理MES系统

RPA原理:简单了解RPA发展及相关知识

八爪鱼采集器︱RPA机器人

RPA 自动化 RPAxAI

数据迁移新技能,MongoDB轻松同步至ClickHouse

RestCloud

数据库 mongodb ETL 数据集成 Click house

Docker通信全视角:原理、实践与技术洞察

不在线第一只蜗牛

Docker 容器 运维

一线实战:运维人少,我们是如何从 0 到 1 实践 DevOps 和云原生?

阿里云云效

阿里云 云原生

基于LangChain手工测试用例转Web自动化测试生成工具

霍格沃兹测试开发学社

一线实战:运维人少,我们是如何从 0 到 1 实践 DevOps 和云原生?

阿里巴巴云原生

阿里云 云原生

Kafka 到数据仓库:使用 bend-ingest-kafka 将消息加载到 Databend

Databend

望繁信科技亮相2024数博会:以流程智能引领数字化转型新未来

望繁信科技

数字化转型 流程挖掘 流程智能 数字北极星 望繁信科技

深入解析RPA:概念、应用和前景一网打尽

八爪鱼采集器︱RPA机器人

RPA 自动化 RPAxAI

新手从零精通云游戏!实测ToDesk云电脑、易腾云、顺网云,云端畅玩黑神话、魔兽世界

小喵子

云计算 云电脑 云游戏 云电竞

如何将文本转换为向量?(方法四)

DashVector

人工智能 向量检索 大模型 向量数据库

RPA技术实操指南:企业降本增效全攻略

八爪鱼采集器︱RPA机器人

RPA 自动化 RPAxAI

从 7000 余项目脱颖而出,飞轮科技《新一代实时分析数据仓库解决方案》荣获 HICOOL 2024 全球创业大赛二等奖

SelectDB

数据仓库 数据分析 Hicool 大数据 开源

SQL 进阶与 MySQL 进阶管理指南

测吧(北京)科技有限公司

测试

企业级低代码解决方案:JNPF平台深度解析

不在线第一只蜗牛

低代码 数字化转型 企业转型

性能最快的内存数据存储:基础使用指南

测吧(北京)科技有限公司

测试

通过DashScope API调用将多种模态转换为向量

DashVector

人工智能 大模型 向量数据库

一文带你了解可观测领域中APM与eBPF的技术差异

乘云数字DataBuff

APM #ebpf

RPA和BPM:优势与特点详解

八爪鱼采集器︱RPA机器人

RPA 自动化 RPAxAI

在 DataOps 体系建设中,主动元数据是何角色?

Aloudata

数据治理 Data 元数据 DataOps

Bonree ONE 3.0发布会下一站 9月6日广州见!

博睿数据

PostgreSQL9.5新特性之行级安全性及其应用级解决方案_数据库_李玉珏_InfoQ精选文章