数据库高安全—角色权限:权限管理权限检查

news2025/1/11 14:34:29

目录

3.3 权限管理

3.4 权限检查


书接上文数据库高安全—角色权限:角色创建角色管理,从角色创建和角色管理两方面对高斯数据库的角色权限进行了介绍,本篇将从权限管理和权限检查方面继续解读高斯数据库的角色权限。

3.3 权限管理

(1) 访问控制列表

访问控制列表(Access Control List,ACL)是实现数据库对象权限管理的基础,每个对象都具有ACL,存储该对象的所有授权信息。当用户访问对象时,只有用户在对象的ACL中并且具有所需的权限才能够访问该对象。

每个ACL是由1个或多个AclItem构成的链表,每1个AclItem由授权者、被授权者和权限位3部分构成,记录着可在对象上进行操作的用户及其权限。

数据结构AclItem:

typedef struct AclItem {    Oid ai_grantee;     // 被授权者的OID     Oid ai_grantor;     // 授权者的OID     AclMode ai_privs;  // 权限位:32位的比特位 } AclItem;

其中ai_privs字段是AclMode类型。AclMode是一个32位的比特位,其高16位为权限选项位,当该比特位取值为1时,表示AclItem中的ai_grantee对应的用户具有此对象的相应操作的授权权限,否则表示用户没有授权权限;低16位为操作权限位,当该比特位取值为1时,表示AclItem中的ai_grantee对应的用户具有此对象的相应操作权限,否则表示用户没有相应的权限。在AclMode的结构位图1中,Grant Option记录各权限的授权权限的授予情况。低16位记录各权限的授予情况,当授权语句使用ALL时,则表示对象的所有权限。

图片

图1 openGauss AclMode结构图

在openGauss的具体实现中,我们将对对象执行DML类操作和DDL类操作的权限分别记在两个AclMode结构中,并以第15位的值来区分二者,最终实现对于每一个数据库对象,相同的授权者和被授权者对应两个不同的AclMode,分别表示记录DML类操作权限和DDL类操作权限,实现方式如图2和图3所示。

图片

图2 openGauss记录DML类操作权限的AclMode结构

图片

图3 openGauss记录DDL类操作权限的AclMode结构

每个权限参数代表的权限如表1所示。

表1 权限参数

参数

对象权限

参数

对象权限

a

INSERT

T

TEMPORARY

r

SELECT

c

CONNECT

w

UPDATE

p

COMPUTE

d

DELETE

R

READ

D

TRUNCATE

W

WRITE

x

REFERENCES

A

ALTER

t

TRIGGER

P

DROP

X

EXECUTE

m

COMMENT

U

USAGE

i

INDEX

C

CREATE

v

VACUUM

(2)对象权限管理

数据库对象权限管理主要通过使用SQL命令GRANT/REVOKE授予或回收一个或多个角色在对象上的权限。GRANT/REVOKE命令都由函数ExecuteGrantStmt实现,该函数只有一个GrantStmt类型的参数,基本流程如图4。

图片

图4 openGauss对象权限管理代码接口

数据结构GrantStmt定义如下:

typedef struct GrantStmt {    NodeTag type;    bool is_grant;            // true = 授权, false = 回收    GrantTargetType targtype;  // 操作目标的类型    GrantObjectType objtype;  // 被操作对象的类型:表,数据库,模式函数等    List* objects;            // 被操作对象的集合    List* privileges;          // 要操作权限列表    List* grantees;           // 被授权者的集合    bool grant_option;       // true = with grant option/grant option for    DropBehavior behavior;   // 回收权限的行为:restrict,cascade} GrantStmt;

函数ExecuteGrantStmt首先将GrantStmt结构转化为InternalGrant结构,将权限列表转化为内部的AclMode表示形式。当privileges 取值为NIL时,表示授予或回收所有的权限,此时置InternalGrant的all_privs字段为true,privileges字段为ACL_NO_RIGHTS。

数据结构InternalGrant:

typedef struct InternalGrant {    bool is_grant;            // true=授权, false=回收    GrantObjectType objtype;  // 被操作对象的类型:表,数据库,模式函数等    List* objects;            // 被操作对象的集合    bool all_privs;           // 是否授予或回收所有的权限AclMode privileges;      // AclMode形式表示的DML类操作对应的权限AclMode ddl_privileges;  // AclMode形式表示的DDL类操作对应的权限List* col_privs;          // 对列执行的DML类操作对应的权限List* col_ddl_privs;      // 对列执行的DDL类操作对应的权限    List* grantees;          // 被授权者的集合    bool grant_option;      // true=with grant option/grant option for    DropBehavior behavior; // 回收权限的行为:restrict,cascade} InternalGrant;

函数ExecuteGrantStmt在完成结构转换之后,调用ExecGrantStmt_oids,根据对象类型分别调用相应对象的权限管理函数。接下来以表对象的权限管理过程为例,介绍权限管理的算法,函数ExecGrant_Relation的处理流程如图5所示。

图片

图5 openGauss表对象权限管理流程图

函数ExecGrant_Relation用来处理表对象权限的授予或回收操作,入参为InternalGrant类型的变量,存储着授权或回收操作的操作对象信息、被授权者信息和权限信息。

  • 首先从系统表pg_class中获取旧ACL,如果不存在旧的ACL,则新建一个ACL,并调用函数acldefault将默认的权限信息赋给该ACL。根据对象的不同,初始的缺省权限含有部分可赋予PUBLIC的权限。如果存在旧的ACL,则将旧的ACL存储为一个副本。

  • 然后调用select_best_grantor来获取授权者对操作对象所拥有的授权权限avail_goptions;将参数avail_goptions传入函数restrict_and_check_grant,结合SQL命令中给出的操作权限,计算出实际需要授予或回收的权限。

  • 再调用merge_acl_with_grant生成新的ACL,如果是授予权限,则将要授予的权限添加到旧ACL中;如果是回收权限,则将要被回收的权限从旧ACL中删除。

  • 最后将新的ACL更新到系统表pg_class对应元组的ACL字段,完成授权或回收过程。

具体的函数实现如下:

static void ExecGrant_Relation(InternalGrant* istmt){    . . .// 循环处理每一个表对象。    foreach (cell, istmt->objects) {        . . .// 判断所要操作的表对象是否存在,若不存在则提示报错。        tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));        if (!HeapTupleIsValid(tuple))            ereport(                ERROR, (errcode(ERRCODE_CACHE_LOOKUP_FAILED), errmsg("cache lookup failed for relation %u", relOid)));        pg_class_tuple = (Form_pg_class)GETSTRUCT(tuple);. . .        // 系统表pg_class中获取旧ACL,若不存在旧的ACL,则新建一个ACL,若存在旧的ACL,则将旧的ACL存储为一个副本。        ownerId = pg_class_tuple->relowner;        aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl, &isNull);        if (isNull) {            switch (pg_class_tuple->relkind) {                case RELKIND_SEQUENCE:                    old_acl = acldefault(ACL_OBJECT_SEQUENCE, ownerId);                    break;                default:                    old_acl = acldefault(ACL_OBJECT_RELATION, ownerId);                    break;            }            noldmembers = 0;            oldmembers = NULL;        } else {            old_acl = DatumGetAclPCopy(aclDatum);            noldmembers = aclmembers(old_acl, &oldmembers);        }        old_rel_acl = aclcopy(old_acl);
        // 处理表级别的权限。        if (this_privileges != ACL_NO_RIGHTS) {            AclMode avail_goptions;            Acl* new_acl = NULL;            Oid grantorId;            HeapTuple newtuple = NULL;            Datum values[Natts_pg_class];            bool nulls[Natts_pg_class] = {false};            bool replaces[Natts_pg_class] = {false};            int nnewmembers;            Oid* newmembers = NULL;            AclObjectKind aclkind;
            // 获取授权者grantorId和授权者对该操作对象所拥有的授权权限avail_goptions。            select_best_grantor(GetUserId(), this_privileges, old_acl, ownerId, &grantorId, &avail_goptions);
            switch (pg_class_tuple->relkind) {                case RELKIND_SEQUENCE:                    aclkind = ACL_KIND_SEQUENCE;                    break;                default:                    aclkind = ACL_KIND_CLASS;                    break;            }
            // 结合参数avail_goptions和SQL命令中给出的操作权限,计算出实际需要授予或回收的权限。            this_privileges = restrict_and_check_grant(istmt->is_grant,                avail_goptions,                istmt->all_privs,                this_privileges,                relOid,                grantorId,                aclkind,                NameStr(pg_class_tuple->relname),                0,                NULL);
            // 生成新的ACL,并更新到系统表pg_class对应元组的ACL字段。            new_acl = merge_acl_with_grant(old_acl,                istmt->is_grant,                istmt->grant_option,                istmt->behavior,                istmt->grantees,                this_privileges,                grantorId,                ownerId);. . .            replaces[Anum_pg_class_relacl - 1] = true;            values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
            newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values, nulls, replaces);
            simple_heap_update(relation, &newtuple->t_self, newtuple);. . .        }
        // 若存在列级授权或回收,则调用ExecGrant_Attribute 函数处理。. . .        if (have_col_privileges) {            AttrNumber i;
            for (i = 0; i < num_col_privileges; i++) {                if (col_privileges[i] == ACL_NO_RIGHTS)                    continue;                ExecGrant_Attribute(istmt,                    relOid,                    NameStr(pg_class_tuple->relname),                    i + FirstLowInvalidHeapAttributeNumber,                    ownerId,                    col_privileges[i],                    attRelation,                    old_rel_acl);            }        }    . . .    }
    heap_close(attRelation, RowExclusiveLock);    heap_close(relation, RowExclusiveLock);}

3.4 权限检查

用户在对数据库对象进行访问操作时,数据库会检查用户是否拥有该对象的操作权限。通常数据库对象的所有者和初始用户(superuser)拥有该对象的全部操作权限,其他普通用户需要被授予权限才可以执行相应操作。数据库通过查询数据库对象的访问控制列表(ACL)检查用户对数据库对象的访问权限,数据库对象的ACL保存在对应的系统表中,当被授予或回收对象权限时,系统表中保存的ACL权限位会被更新。常用的数据库对象权限检查函数、ACL检查函数、ACL所在系统表以及对象所有者检查函数对应关系如表2所示。

表2 数据库对象函数对应关系表

对象

权限检查

ACL检查

所有者检查

系统表

table

pg_class_aclcheck

pg_class_aclmask

pg_class_ownercheck

pg_class

column

pg_attribute_aclcheck

pg_attribute_aclmask

NA

pg_attribute

database

pg_database_aclcheck

pg_database_aclmask

pg_database_ownercheck

pg_database

function

pg_proc_aclcheck

pg_proc_aclmask

pg_proc_ownercheck

pg_proc

language

pg_language_aclcheck

pg_language_aclmask

pg_language_ownercheck

pg_language

largeobject

pg_largeobject_aclcheck_snapshot

pg_largeobject_aclmask_snapshot

pg_largeobject_ownercheck

pg_largeobject_metadata

namespace

pg_namespace_aclcheck

pg_namespace_aclmask

pg_namespace_ownercheck

pg_namespace

tablespace

pg_tablespace_aclcheck

pg_tablespace_aclmask

pg_tablespace_ownercheck

pg_tablespace

foreign data wrapper

pg_foreign_data_wrapper_aclcheck

pg_foreign_data_wrapper_aclmask

pg_foreign_data_wrapper_ownercheck

pg_foreign_data_wrapper

foreign server

pg_foreign_server_aclcheck

pg_foreign_server_aclmask

pg_foreign_server_ownercheck

pg_foreign_server

type

pg_type_aclcheck

pg_type_aclmask

pg_type_ownercheck

pg_type

下面以表的权限检查为例进行权限检查过程说明。表权限检查函数pg_class_aclcheck定义如下:

AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode, bool check_nodegroup){    if (pg_class_aclmask(table_oid, roleid, mode, ACLMASK_ANY, check_nodegroup) != 0)        return ACLCHECK_OK;    else        return ACLCHECK_NO_PRIV;}

pg_class_aclcheck函数有4个入参,其中table_oid用于表示待检查的表,roleid用于表示待检查的用户或角色,mode表示待检查的权限,此权限可以是一种权限也可以是多种权限的组合。第4个参数check_nodegroup用于表示是否检查nodegroup逻辑集群权限,如果调用时不给此参数赋值则默认为true。函数返回值为枚举类型AclResult,如果检查结果有权限返回ACLCHECK_OK,无权限则返回ACLCHECK_NO_PRIV。

pg_class_aclcheck函数通过调用pg_class_aclmask函数实现对象权限检查。pg_class_aclmask函数有5个参数,其中第4个参数how为AclMaskHow枚举类型,包括ACLMASK_ALL和ACLMASK_ANY两种取值,ACLMASK_ALL表示需要满足待检查权限mode中的所有权限,ACLMASK_ANY表示只需满足待检查权限mode中的一种权限即可。pg_class_aclmask函数的其余4个参数table_oid、roleid、mode和check_nodegroup直接由pg_class_aclcheck函数传入。pg_class_aclmask函数从“pg_class”系统表中获取ACL权限信息并调用aclmask函数完成权限位校验,通过AclMode数据类型返回权限检查结果。

以上内容从权限管理和权限检查两方面对角色权限进行了介绍,下篇将从传统审计和统一审计两方面对高斯数据库的审计追踪技术进行解读,敬请期待~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2274953.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据集-目标检测系列- 石榴 检测数据集 pomegranate >> DataBall

数据集-目标检测系列- 石榴 检测数据集 pomegranate >> DataBall DataBall 助力快速掌握数据集的信息和使用方式&#xff0c;会员享有 百种数据集&#xff0c;持续增加中。 需要更多数据资源和技术解决方案&#xff0c;知识星球&#xff1a; “DataBall - X 数据球(fre…

搭建一个本地轻量级且好用的学习TypeScript语言的环境

需求说明 虽然 TypeScript 的在线 Playground 很方便 https://www.tslang.com.cn/play/&#xff0c;但毕竟是在浏览器中使用&#xff0c;没有本地的 IDE 那么顺手。所以我想搭建一个本地类似 Playground 的环境&#xff0c;这样在学习 TypeScript 的过程中&#xff0c;可以更方…

项目管理之引论

在当今这个快速变化、竞争激烈的商业环境中&#xff0c;项目管理已经成为组织实现目标、提升竞争力的关键手段。无论是企业的新产品研发、建筑项目的施工&#xff0c;还是政府部门的公共服务项目推进&#xff0c;都离不开有效的项目管理。以下是我对项目管理的一些初步见解和认…

20250109使用M6000显卡在Ubuntu20.04.6下跑whisper来识别中英文字幕

20250109使用M6000显卡在Ubuntu20.04.6下跑whisper来识别中英文字幕 2025/1/9 20:57 https://blog.csdn.net/wb4916/article/details/144541848 20241217使用M6000显卡在WIN10下跑whisper来识别中英文字幕 步骤&#xff1a; 1、在NVIDIA的官网下载并安装M6000显卡在WIN10下的最…

Windows service运行Django项目

系统&#xff1a;Windows Service 软件&#xff1a;nssm&#xff0c;nginx 配置Django项目 1、把Django项目的静态文件整理到staticfiles文件夹中 注&#xff1a;settings中的设置 STATIC_URL /static/ STATIC_ROOT os.path.join(BASE_DIR, staticfiles/) STATICFILES_DI…

关于物联网的基础知识(二)——物联网体系结构分层

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///计算机爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于物联网的基础知识&#xff08;二&a…

【C++】22.AVL树实现

文章目录 1. AVL的概念AVL树的逻辑理解四种形式1. LL型&#xff08;左孩子的左子树上出现节点使结点失衡&#xff09;2. RR型&#xff08;右孩子的右子树上出现节点使结点失衡&#xff09;3. LR型&#xff08;左孩子的右子树上出现节点使结点失衡&#xff09;4. RL型&#xff0…

php文件包含漏洞

基本 相关函数 php中引发文件包含漏洞的通常是以下四个函数&#xff1a; include()include_once()require()require_once() reuqire() 如果在包含的过程中有错&#xff0c;比如文件不存在等&#xff0c;则会直接退出&#xff0c;不执行后续语句。 include() 如果出错的话&a…

ELK实战(最详细)

一、什么是ELK ELK是三个产品的简称&#xff1a;ElasticSearch(简称ES) 、Logstash 、Kibana 。其中&#xff1a; ElasticSearch&#xff1a;是一个开源分布式搜索引擎Logstash &#xff1a;是一个数据收集引擎&#xff0c;支持日志搜集、分析、过滤&#xff0c;支持大量数据…

预训练语言模型——BERT

1.预训练思想 有了预训练就相当于模型在培养大学生做任务&#xff0c;不然模型初始化再做任务就像培养小学生 当前数据层面的瓶颈是能用于预训练的语料快被用完了 现在有一个重要方向是让机器自己来生成数据并做微调 1.1 预训练&#xff08;Pre - training&#xff09;vs. 传…

ElasticSearch 认识和安装ES

文章目录 一、为什么学ElasticSearch?1.ElasticSearch 简介2.ElasticSearch 与传统数据库的对比3.ElasticSearch 应用场景4.ElasticSearch 技术特点5.ElasticSearch 市场表现6.ElasticSearch 的发展 二、认识和安装ES1.认识 Elasticsearch&#xff08;简称 ES&#xff09;2.El…

mysql和redis的最大连接数

平时我们要评估mysql和redis的最大连接数&#xff0c;可以选择好环境&#xff08;比如4核8G&#xff09;,定好压测方法&#xff08;没有索引的mysql单表&#xff0c;redis单key&#xff09;进行压测&#xff0c;评估其最大并发量。 也可以查看各大云厂商的规格进行评估。 mys…

2025年中科院分区大类划分公布!新增8155本

2025年中科院分区表变更情况 扩大收录范围 2025年的期刊分区表在原有的自然科学&#xff08;SCIE&#xff09;、社会科学&#xff08;SSCI&#xff09;和人文科学&#xff08;AHCI&#xff09;的基础上&#xff0c;增加了ESCI期刊的收录&#xff0c;并根据这些期刊的数据进行…

机器人避障不再“智障”:HEIGHT——拥挤复杂环境下机器人导航的新架构

导读&#xff1a; 由于环境中静态障碍物和动态障碍物的约束&#xff0c;机器人在密集且交互复杂的人群中导航&#xff0c;往往面临碰撞与延迟等安全与效率问题。举个简单的例子&#xff0c;商城和车站中的送餐机器人往往在人流量较大时就会停在原地无法运作&#xff0c;因为它不…

Spring Boot教程之五十二:CrudRepository 和 JpaRepository 之间的区别

Spring Boot – CrudRepository 和 JpaRepository 之间的区别 Spring Boot建立在 Spring 之上&#xff0c;包含 Spring 的所有功能。由于其快速的生产就绪环境&#xff0c;使开发人员能够直接专注于逻辑&#xff0c;而不必费力配置和设置&#xff0c;因此如今它正成为开发人员…

加速物联网HMI革命,基于TouchGFX的高效GUI显示方案

TouchGFX 是一款针对 STM32 微控制器优化的先进免费图形软件框架。 TouchGFX 利用 STM32 图形功能和架构&#xff0c;通过创建令人惊叹的类似智能手机的图形用户界面&#xff0c;加速了物联网 HMI 革命。 TouchGFX 框架包括 TouchGFX Designer (TouchGFXDesigner)&#xff08;…

Java-数据结构-栈与队列(StackQueue)

一、栈(Stack) ① 栈的概念 栈是一种特殊的线性表&#xff0c;它只允许固定一端进行"插入元素"和"删除元素"的操作&#xff0c;这固定的一端被称作"栈顶"&#xff0c;对应的另一端就被称做"栈底"。 &#x1f4da; 栈中的元素遵循后…

案例研究:UML用例图中的结账系统

在软件工程和系统分析中&#xff0c;统一建模语言&#xff08;UML&#xff09;用例图是一种强有力的工具&#xff0c;用于描述系统与其用户之间的交互。本文将通过一个具体的案例研究&#xff0c;详细解释UML用例图的关键概念&#xff0c;并说明其在设计结账系统中的应用。 用…

【动态规划篇】欣赏概率论与镜像法融合下,别出心裁探索解答括号序列问题

本篇鸡汤&#xff1a;没有人能替你承受痛苦&#xff0c;也没有人能拿走你的坚强. 欢迎拜访&#xff1a;羑悻的小杀马特.-CSDN博客 本篇主题&#xff1a;带你解答洛谷的括号序列问题&#xff08;绝对巧解&#xff09; 制作日期&#xff1a;2025.01.10 隶属专栏&#xff1a;C/C题…

点击底部的 tabBar 属于 wx.switchTab 跳转方式,目标页面的 onLoad 不会触发(除非是第一次加载)

文章目录 1. tabBar 的跳转方式2. tabBar 跳转的特点3. 你的配置分析4. 生命周期触发情况5. 总结 很多人不明白什么是第一次加载&#xff0c;两种情况讨论&#xff0c;第一种情况假设我是开发者&#xff0c;第一次加载就是指点击微信开发者工具上边的编译按钮&#xff0c;每点击…