【安全审计】PG行级安全策略(RLS)

一、概述

RLS(ROW Level Security) 是PostgreSQL 9.5版本中新增特性,提供了基于行的安全策略,它针对每一个用户限制哪些行可以 被普通的查询返回或者可以被数据修改命令插入、更新或删除。当在一个表上启用行安全性时,所有对该表选择行或者修改行的普通访问都必须被一条 行安全性策略所允许(不过,表的拥有者通常不服从行安全性策略)。

只有所有者才具有启用 / 禁用行级安全性,给表添加策略的权限。

常见命令:

CREATE POLICY :创建策略
ALTER POLICY :修改策略
DROP POLICY :删除策略
ALTER TABLE :用于行级安全性的启用 / 禁用。

二、DML涉及的主要函数

位于src/backend/rewrite/rowsecurity.c

void
get_row_security_policies(Query *root, RangeTblEntry *rte, int rt_index,
						  List **securityQuals, List **withCheckOptions,
						  bool *hasRowSecurity, bool *hasSubLinks)

主要逻辑:

  1. 初始化返回值:将返回值初始化为空列表或 false。
  2. 检查是否为普通关系:如果不是普通表或分区表,则直接返回。
  3. 获取用户 ID:使用 rte->checkAsUser 或当前用户的 ID。
  4. 检查行级安全状态:调用 check_enable_rls 函数检查是否启用行级安全。
  5. 获取行级安全策略:根据命令类型和用户 ID 获取行级安全策略。
  6. 添加安全限定条件:将行级安全策略的 USING 子句添加到查询中。
  7. 添加 WITH CHECK 选项:将行级安全策略的 WITH CHECK 子句添加到查询中。
  8. 处理特殊情况:如 SELECT 时需要 UPDATE 权限、INSERT … ON CONFLICT DO UPDATE 和MERGE。
  9. 关闭关系:关闭打开的关系。
  10. 设置 checkAsUser:将 checkAsUser 设置到安全限定条件和 WITH CHECK 选项中。
  11. 标记查询为行级安全:标记查询为行级安全,以便在环境变化时重新计划查询。
    这个函数确保了只有符合行级安全策略的行才能被用户访问或修改。

三、ALTER TABLE语句涉及的函数

位于src/backend/commands/tablecmds.c

static void
ATExecSetRowSecurity(Relation rel, bool rls)
{
	Relation	pg_class;
	Oid			relid;
	HeapTuple	tuple;

	relid = RelationGetRelid(rel);

	/* Pull the record for this relation and update it */
	pg_class = table_open(RelationRelationId, RowExclusiveLock);

	tuple = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));

	if (!HeapTupleIsValid(tuple))
		elog(ERROR, "cache lookup failed for relation %u", relid);

	((Form_pg_class) GETSTRUCT(tuple))->relrowsecurity = rls;
	CatalogTupleUpdate(pg_class, &tuple->t_self, tuple);

	table_close(pg_class, RowExclusiveLock);
	heap_freetuple(tuple);
}

主要逻辑:

  1. 获取表的 OID。
  2. 打开系统目录 pg_class 并获取锁。
  3. 从系统缓存中查找表的元组。
  4. 修改元组中的 relrowsecurity 字段。
  5. 将修改后的元组写回到系统目录中。
  6. 关闭系统目录并释放锁。
  7. 释放元组。
    这个函数是 PostgreSQL 内部实现行级安全策略的关键部分。通过修改 pg_class 表中的 relrowsecurity 字段,可以控制表是否启用行级安全策略。

四、CREATE POLICY涉及的函数

位于src/backend/commands/policy.c

ObjectAddress
CreatePolicy(CreatePolicyStmt *stmt)

主要逻辑:

  1. 解析命令类型和条件。
  2. 检查命令类型和条件的合法性。
  3. 获取表的 OID,并打开目标表。
  4. 解析 USING 和 WITH CHECK 条件。
  5. 打开系统表 pg_policy,并检查是否已存在同名策略。
  6. 插入新的策略元组到系统表。
  7. 记录依赖关系。
  8. 使缓存失效。
  9. 清理资源并返回新策略的对象地址。

五、ALTER POLICY涉及的函数

位于 src/backend/commands/policy.c

ObjectAddress
AlterPolicy(AlterPolicyStmt *stmt)

主要逻辑:
解析角色列表和条件表达式。
获取表的 OID,并打开目标表。
解析 USING 和 WITH CHECK 条件。
打开系统表 pg_policy,并查找指定的策略。
更新策略的字段(如角色列表、USING 条件、WITH CHECK 条件)。
更新依赖关系。
使缓存失效。
清理资源并返回修改后的策略的对象地址。

六、DROP POLICY涉及的函数

位于src/backend/commands/policy.c

void
RemovePolicyById(Oid policy_id)

主要逻辑:

  1. 打开系统表 pg_policy,并获取锁。
  2. 查找指定 OID 的策略。
  3. 检查策略是否存在。
  4. 获取策略所属的表,并检查表的类型和权限。
  5. 删除策略。
  6. 使缓存失效。
  7. 清理资源并关闭表和系统表。

作者介绍

葛文龙,移动云数据库助理工程师,负责云原生数据库He3DB的研发。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值