PostgreSQL学习笔记----对象访问控制

在 PostgreSQL中,建立安全的数据库连接是由用户标识和认证技术来共同实现,而建立连接后的安全访问保护则是基于角色的对象访问控制。

数据库里的每个对象所拥有的权限信息经常会发生变化,比如授予对象的部分操作权限给其他用户,或者删除用户在对象上的操作权限,亦或是对用户在对象上的操作权限进行更新等。以上操作在 SQL 中体现为 GRANT 和 REVOKE 语句,且都涉及对象权限信息的动态管理,即权限控制中的对象权限管理。

为了保护数据安全,当用户要对某个数据库对象进行操作之前,必须检查用户在对象上的操作权限,仅当用户对此对象拥有进行合法操作的权限时,才允许用户对此对象执行相应操作。上述操作检查的过程被称为对象权限检查。

ACL

访问控制列表(Access Control List,ACL)是对象权限管理和权限检查的基础,PostgreSQL 通过操作 ACL 实现对象的访问控制管理,在 PostgreSQL 中每个数据库对象都具有 ACL ,每个对象的 ACL 存储了此对象的所有授权信息。当用户访问对象时,只有它在对象的 ACL 中并且具有所需的权限时才能访问该对象。当用户要更新对象的权限时,只需要更新 ACL 上的权限信息即可。

ACL 是存储控制项(Access Control Entruy,ACE)的集合,组织结构如图(取自《PostgreSQL 数据库内核分析》):
在这里插入图片描述
每个 ACL 实际是一个由多个 AclItem 构成的链表。每个 AclItem 对应一个 ACE 。 ACE 中记录着可访问对象的用户或者执行单元,此外还记录了可在对象上进行权限操作的用户或者执行单元。PostgreSQL 中,ACE 由受权者、授权者以及权限位三部分组成。

/*
 * AclItem
 *
 * Note: must be same size on all platforms, because the size is hardcoded
 * in the pg_type.h entry for aclitem.
 */
typedef struct AclItem
{
   
	Oid			ai_grantee;		/* ID that this item grants privs to */
	Oid			ai_grantor;		/* grantor of privs */
	AclMode		ai_privs;		/* privilege bits */
} AclItem;

其中,字段 ai_privs 是 AclMode 类型。AclMode 是一个 32 位的比特位,其高 16 位为权限选项位,低 16 位为该 ACE 中的操作位权限。每个操作权限占 1 个比特位,当该比特位的取值为 1 时,表示 ACE 中的 ai_grabtee 对应的用户(受权者)具有此对象的相应操作权限,否则,表示用户没有相应权限。AclMode 结构如下所示(取自《PostgreSQL 数据库内核分析》):
在这里插入图片描述
ace type:记录了 ACE 的被授权者(受权者)类型,可以是用户、组或者 public。
Grant options:记录了各权限位对应的授出或者被转授选项。
低 16 位:分别记录了各个权限位的授予情况,从低到高依次为 INSERT、SELECT、UPDATE、DELETE、TRUNCATE 等等。若当授予语句使用 ALL 时,则表示包含所有权限。

ACL 检查

调用 src/backend/catalog/aclchk.c 下的函数 pg_class_aclcheck ,获取用户在该表上的权限集,比较该权限集与操作所需权限集,若前者大于后者,则检查通过。

首先获取到对应的元组,从 pg_class 系统表中:

	/*
	 * Must get the relation's tuple from pg_class
	 */
	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
	if (!HeapTupleIsValid(tuple))
	{
   
		if (is_missing != NULL)
		{
   
			/* return "no privileges" instead of throwing an error */
			*is_missing = true;
			return 0;
		}
		else
			ereport(ERROR,
					(errcode(ERRCODE_UNDEFINED_TABLE),
					 errmsg("relation with OID %u does not exist",
							table_oid)));
	}

	classForm = (Form_pg_class) GETSTRUCT(tuple);

判断操作的表是否是系统表,如果是系统表则禁止操作。通过 IsSystemClass 函数判断其 relid 是否小于 FirstUnpinnedObjectId。

/*
	 * Deny anyone permission to update a system catalog unless
	 * pg_authid.rolsuper is set.
	 *
	 * As of 7.4 we have some updatable system views; those shouldn't be
	 * protected in this way.  Assume the view rules can take care of
	 * themselves.  ACL_USAGE is if we ever have system sequences.
	 */
	if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
		IsSystemClass(table_oid, classForm) &&
		classForm->relkind != RELKIND_VIEW &&
		!superuser_arg(roleid))
		mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE);

从 pg_class 系统表中取出操作表的 ACL ,产生一个副本

	/*
	 * Normal case: get the relation's ACL from pg_class
	 */
	ownerId = classForm->relowner;

	aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
							   &isNull);
	if (isNull)
	{
   
		/* No ACL, so build default ACL */
		switch (classForm->relkind)
		{
   
			case RELKIND_SEQUENCE:
				acl = acldefault(OBJECT_SEQUENCE, ownerId
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

aSimpleSheep

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值