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

目录

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.rhkb.cn/news/505689.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入浅出负载均衡:理解其原理并选择最适合你的实现方式

负载均衡是一种在多个计算资源&#xff08;如服务器、CPU核心、网络链接等&#xff09;之间分配工作负载的技术&#xff0c;旨在优化资源利用率、提高系统吞吐量和降低响应时间。负载均衡的实现方式多种多样&#xff0c;以下是几种常见的实现方式&#xff1a; 1. 硬件负载均衡&…

Training-free regional prompting for diffusion transformers

通过语言模型来构建位置关系的,omnigen combine来做位置生成,其实可以通过大模型来做,不错。 1.introduction 文生图模型在准确处理具有复杂空间布局的提示时仍然面临挑战,1.通过自然语言准确描述特定的空间布局非常困难,特别是当对象数量增加或需要精确的位置控制时,2.…

麦田物语学习笔记:背包物品选择高亮显示和动画

如题,本篇文章没讲动画效果 基本流程 1.代码思路 (1)先用点击事件的接口函数去实现,点击后反转选择状态(isSelected),以及设置激活状态(SetActive),并且还需要判断该格子是否为空,空格子是点不动的,完成后以上后,出现的问题是高亮应该是有且仅有一个格子是高亮的,而现在可以让…

Linux:深入了解fd文件描述符

目录 1. 文件分类 2. IO函数 2.1 fopen读写模式 2.2 重定向 2.3 标准文件流 3. 系统调用 3.1 open函数认识 3.2 open函数使用 3.3 close函数 3.4 write函数 3.5 read函数 4. fd文件描述符 4.1 标准输入输出 4.2 什么是文件描述符 4.3 语言级文件操作 1. 文件分类…

数据结构:栈(Stack)和队列(Queue)—面试题(一)

目录 1、括号匹配 2、逆波兰表达式求值 3、栈的压入、弹出序列 4、最小栈 1、括号匹配 习题链接https://leetcode.cn/problems/valid-parentheses/description/ 描述&#xff1a; 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] …

51单片机(一) keil4工程与小灯实验

直接开始 新建一个工程 在这里插入图片描述 添加文件 另存为 添加文件到组 写下一个超循环系统代码 调整编译项编译 可以在工程目录找到编译好的led_fst.hex 自行烧写到各自的开发板。 会看到什么都没有。 现在定义一个GPIO端口与小灯的连接&#xff0c;再点亮小灯…

基于 Python 和 OpenCV 的人脸识别上课考勤管理系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

Vue2:el-table中的文字根据内容改变颜色

想要实现的效果如图,【级别】和【P】列的颜色根据文字内容变化 1、正常创建表格 <template><el-table:data="tableData"style="width: 100%"><el-table-column prop="id" label="ID"/> <el-table-column …

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

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

73.矩阵置零 python

矩阵置零 题目题目描述示例 1&#xff1a;示例 2&#xff1a;提示&#xff1a; 题解思路分析Python 实现代码代码解释提交结果 题目 题目描述 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例…

C++【深入底层,从零模拟实现string类】

在学习了类和对象、模板等前期的C基础知识之后&#xff0c;我们可以尝试根据C标准库中所提供的接口类型&#xff0c;来搭建我们自己的string类型。这个过程有助于初学者掌握C的基础语法及底层逻辑。 框架的搭建 首先搭建模型的基础框架&#xff0c;需要建立my_string.h和my_st…

切忌 SELECT *,就算表只有一列

原文地址 尽量避免 SELECT *&#xff0c;即使在单列表上也是如此 – 如果你现在不同意这一点&#xff0c;读完这篇文章&#xff0c;你可能就要动摇了。 2012年的一个故事 这是我 12 年前&#xff08;约 2012-2013 年&#xff09;在客户后台应用程序中遇到的一个真实故事。 当…

DEV C++软件下载

一、进入网站 https://sourceforge.net/projects/orwelldevcpp/ 二、点击下载 三、安装步骤 1、点击 “OK” 2、点击“I agree” 3、点击“Next” 4、按步骤切换路径&#xff0c;本文选在D盘&#xff0c;可自行选取文件路径 5、等待安装 6、点击完成 7、选择语言 8、点击“N…

OpenBSD之安装指南

安装介质下载 OpenBSD的官网下载地址&#xff1a;https://www.openbsd.org/faq/faq4.html#Download&#xff0c;同时也是《OpenBSD FAQ - Installation Guide》。长篇大论了很多&#xff0c;每一个章节都能看懂是干嘛的&#xff0c;连起来就容易晕。并且是英文的&#xff0c;要…

Vue.config.productionTip = false 不起作用的问题及解决

文章目录 一、问题描述二、解决方法 一、问题描述 当我们在代码页面上引入Vue.js(开发版本)时&#xff0c;运行代码会出现以下提示&#xff0c;这句话的意思是&#xff1a;您正在开发模式下运行Vue&#xff0c;在进行生产部署时&#xff0c;请确保打开生产模式 You are runni…

C#,图论与图算法,输出无向图“欧拉路径”的弗勒里(Fleury Algorithm)算法和源程序

1 欧拉路径 欧拉路径是图中每一条边只访问一次的路径。欧拉回路是在同一顶点上开始和结束的欧拉路径。 这里展示一种输出欧拉路径或回路的算法。 以下是Fleury用于打印欧拉轨迹或循环的算法&#xff08;源&#xff09;。 1、确保图形有0个或2个奇数顶点。2、如果有0个奇数顶…

oracle闪回表

文章目录 闪回表案例1&#xff1a;&#xff08;未清理回收站时的闪回表--成功&#xff09;案例2&#xff08;清理回收站时的闪回表--失败&#xff09;案例3&#xff1a;彻底删除表&#xff08;不经过回收站--失败&#xff09;案例4&#xff1a;闪回表之后重新命名新表总结1、删…

CSS——22.静态伪类(伪类是选择不同元素状态)

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>静态伪类</title> </head><body><a href"#">我爱学习</a></body> </html>单击链接前的样式 左键单击&#xff08;且…

Java Spring Boot实现基于URL + IP访问频率限制

点击下载《Java Spring Boot实现基于URL IP访问频率限制(源代码)》 1. 引言 在现代 Web 应用中&#xff0c;接口被恶意刷新或暴力请求是一种常见的攻击手段。为了保护系统资源&#xff0c;防止服务器过载或服务不可用&#xff0c;需要对接口的访问频率进行限制。本文将介绍如…

数据结构(Java版)第七期:LinkedList与链表(二)

专栏&#xff1a;数据结构(Java版) 个人主页&#xff1a;手握风云 一、链表的实现&#xff08;补&#xff09; 接上一期&#xff0c;下面我们要实现删除所有值为key的元素&#xff0c;这时候有的老铁就会想用我们上一期中讲到的remove方法&#xff0c;循环使用remove方法&#…