数据库高安全—数据保护:数据动态脱敏
书接上文数据库高安全—审计追踪:传统审计&统一审计,从传统审计和统一审计两方面对高斯数据库的审计追踪技术进行解读,本篇将从数据动态脱敏方面对高斯数据库的数据保护技术进行解读。
5.1 数据动态脱敏
数据脱敏,顾名思义就是将敏感数据通过变形、屏蔽等方式处理,其目的是保护隐私数据信息,防止数据泄露和恶意窥探。当企业或者机构收集用户个人身份数据、手机、银行卡号等敏感信息,然后将数据通过导出(非生产环境)或直接查询(结合生产环境)的方式投入使用时,按照隐私保护相关法律法规需将数据进行“脱敏”处理。
openGauss实现了数据动态脱敏机制,它根据一系列用户配置的“脱敏策略”来对查询命令进行分析匹配,最终将敏感数据屏蔽并返回。使用数据动态脱敏特性总的来说分为两个步骤:配置脱敏策略、触发脱敏策略。本小节将对这两个步骤进行具体分析。
显然,只有在配置脱敏策略后系统才能有根据地进行敏感数据脱敏。openGauss提供了脱敏策略配置(创建、修改、删除)语法,这些语法所涉及的语法解析结点内容大致相同,因此这里仅对创建策略相关数据结构进行分析,其余不再赘述。下面将结合一个具体示例对数据动态脱敏特性进行详细介绍。
表1给出了一张包含敏感信息(薪资、银行卡号)的个人信息表,策略管理员要对该表中的敏感信息创建脱敏策略:当用户user1或user2在IP地址10.123.123.123上使用jdbc或gsql连接数据库并查询个人信息表时,系统将自动屏蔽敏感信息。
表1 个人信息表person
| id | name | gender | salary | creditcards |
| 1 | 张三 | 男 | 10000 | 6210630600006321083 |
| 2 | 李四 | 男 | 15000 | 6015431250003215514 |
| 3 | 王五 | 女 | 20000 | 5021134522201529881 |
首先策略管理员需要对敏感列打标签,随后使用标签创建脱敏策略,策略配置DDL语句如下:
例1脱敏策略配置示例。
配置资源标签:
CREATE RESOURCE LABEL salary_label ADD COLUMN(person.salary);CREATE RESOURCE LABEL creditcard_label ADD COLUMN(person.creditcards);
配置脱敏策略:
CREATE MASKING POLICY mask_person_policy MASKALL ON LABEL(salary_label), CREDITCARDMASKING ON label(creditcard_label) FILTER ON ROLES(user1,user2), IP(‘10.123.123.123’), APP(jdbc, gsql);
user1在10.123.123.123地址使用gsql查询敏感数据:
SELECT id, salary, creditcards from public.person;
下面将对CREATE MASKING POLICY语句所涉及的语法结构定义进行逐一介绍。
数据结构CreateMaskingPolicyStmt:
typedef struct CreateMaskingPolicyStmt{NodeTag type;char *policy_name; // 脱敏策略名称List *policy_data; // 脱敏策略行为List *policy_filters; // 用户过滤条件bool policy_enabled; // 策略开关} CreateMaskingPolicyStmt;
脱敏策略创建语法是对CreateMaskingPolicyStmt进行填充,其中policy_data是由若干DefElem节点组成的List,每个DefElem指出了以何种方式脱敏数据库资源,DefElem->name标识脱敏方法,DefElem->arg代表脱敏对象。
数据动态脱敏中例1脱敏策略配置示例的步骤(3) 对应的policy_data组织结构如图1所示。

图1 脱敏策略配置示例对应的policy_data组织结构
policy_filters描述了脱敏策略生效的用户场景(用户名、客户端、登录IP),该List只有一个节点,是Policy Filter前缀逻辑树的根节点,只有当用户信息满足逻辑树所描述的场景时,其相应的脱敏策略才会生效。Policy Filter逻辑树节点如下所示:
typedef struct PolicyFilterNode{NodeTag type;char *node_type; // 逻辑操作类型,取值为“op”或“filter”char *op_value; // 逻辑操作符,仅当node_type为op时取值为“and”或“or”,否则为NULLchar *filter_type;// 过滤数据类型,仅当node_type为filter时取值为“APP”、“ROLES”、“IP”List *values; // 过滤数据值List,指出具体的过滤条件值,若node_type为op时置NULLNode *left; // 左子树Node *right; // 右子树} PolicyFilterNode;
逻辑树节点分为操作符(op)节点和过滤数据(filter)节点,当op节点分为“与”或“或”关系,其op_value将置为“and”或“or”,其左右子树代表操作符左右子表达式。filter节点一般作为op的叶子节点出现,它标识具体的过滤信息并将其值存放在values链表中。需要注意的是,一个节点不可能既是op节点又是filter节点。数据动态脱敏中例1脱敏策略配置示例的步骤(3) 对应的policy_filters组织结构如图2所示。

图2 配置脱敏策略对应的policy_filter组织结构
脱敏策略配置的总体流程如图3所示。

图3 脱敏策略配置流程图
在查询编译脱敏策略配置SQL之后将进入策略增删改主函数中,首先会根据语法解析节点校验相关参数的合法性,做如下检查:
-
检查脱敏策略指定的数据库资源是否存在。
-
检查脱敏函数是否存在。
-
检查脱敏策略是否已存在。
-
检查脱敏相关约束:脱敏对象必须为基本表的数据列、脱敏列类型必须满足规格限制、脱敏列只允许加载一个脱敏函数。
-
检查Masking Filter是否冲突,不允许同一数据库资源在相同用户场景下触发多个策略。
其中Masking Filter冲突校验的目的是为了防止用户场景同时满足多个脱敏策略限制,导致策略匹配时系统无法判断应该触发哪种脱敏策略。因此在创建策略时要保证其Filter与现存的策略互斥,主要是判断是否存在一种用户场景能够同时满足多个MASKING FILTER。在数据动态脱敏所示的表2数据基础上,如下表中策略A和策略B是相互冲突的,而策略A和策略C是互斥的。
脱敏策略冲突或互斥场景:
策略A:CREATE MASKING POLICY mask_A MASKALL ON LABEL(creditcard_label) FILTER ON IP(’10.123.123.123’), APP(jdbc), ROLES(user1);策略B:CREATE MASKING POLICY mask_B CREDITCARDMASKING ON LABEL(creditcard_label) FILTER ON IP(’10.123.123.123’,’10.90.132.132’), APP(jdbc, gsql), ROLES(user1);策略C:CREATE MASKING POLICY mask_C CREDITCARDMASKING ON LABEL(creditcard_label) FILTER ON IP(’10.123.123.123’ ,’10.90.132.132’), APP(jdbc), ROLES(user2);
随后将依据策略配置信息更新系统表:
-
更新gs_masking_policy系统表,存储policy基本信息。
-
更新gs_masking_policy_actions系统表,存储策略对应的脱敏方式及脱敏对象。
-
更新gs_masking_policy_filter系统表,存储脱敏用户场景过滤信息,此时会将逻辑树转换为逻辑表达式字符串进行存储,在之后的敏感数据访问时该字符串将会重新转换为逻辑树进行场景校验。
为了降低策略读取IO损耗,openGauss维护了一组线程级别的策略缓存,用于保存已配置的脱敏策略,并在策略配置后进行实时刷新。
在用户进行数据查询时,数据动态脱敏特性使用openGauss的HOOK机制,将查询编译生成的查询树(Query)钩取出来与脱敏策略进行匹配,最后将查询树按照脱敏策略内容改写成不包含敏感数据的“脱敏”查询树返还给解析层继续执行,最终实现屏蔽敏感数据的能力。其执行流程图如4所示。

图4 脱敏策略执行流程图
在对一个访问数据库资源的查询树进行脱敏之前,需要准备一份待匹配的脱敏策略集合,其依据就是用户登录信息,check_masking_policy_filter函数的任务就是将用户信息与所有的脱敏策略进行匹配,筛选出可能被查询触发的脱敏策略。最终筛选如下脱敏策略:
-
若脱敏策略没有配置FILTER信息,说明对所有用户生效。
-
若当前用户信息与脱敏策略的FILTER匹配,则说明对当前用户生效。
在每个脱敏策略从系统表读入缓存时,需要将对应的FILTER逻辑表达式转换为逻辑树并将逻辑树根节点存入缓存中,将其作为脱敏策略筛选条件,逻辑树结构如下。
class PolicyLogicalTree {public:…bool parse_logical_expression(const gs_stl::gs_string logical_expr_str); // 逻辑表达式构造逻辑树入口函数bool match(const FilterData *filter_item);bool has_intersect(PolicyLogicalTree *arg);private:gs_stl::gs_vector<PolicyLogicalNode> m_nodes; // 逻辑节点集合,包含了逻辑树中所有的节点gs_stl::gs_vector<int> m_flat_tree; // 利用数组将逻辑节点索引构造逻辑二叉树// 逻辑表达式转换为逻辑树的递归函数。bool parse_logical_expression_impl(const gs_stl::gs_string logical_expr_str, int *offset, int *idx, Edirection direction);inline void create_node(int *idx, EnodeType type, bool has_operator_not); // 创建单个逻辑树节点void flatten_tree(); // 将逻辑树刷新到m_nodes集合与m_flat_tree索引中bool check_apps_intersect(string_sort_vector*, string_sort_vector*);bool check_roles_intersect(oid_sort_vector*, oid_sort_vector*);bool m_has_ip; // 标识整个逻辑树是否涉及ip校验bool m_has_role; // 标识整个逻辑树是否涉及用户名校验bool m_has_app; // 标识整个逻辑树是否涉及客户端校验};
逻辑树节点的结构与语法解析中的FILTER节点类似,具体可以参照PolicyFilterNode结构。
struct PolicyLogicalNode {...EnodeType m_type;int m_left; // 左子节点索引int m_right; // 右子节点索引void make_eval(const FilterData *filter_item); //判断用户信息是否满足本节点子树表示的逻辑。bool m_eval_res;oid_sort_vector m_roles; // 本节点包含的用户名集合string_sort_vector m_apps; // 本节点包含的客户端名称集合IPRange m_ip_range; //本节点包含的IP};
当需要将逻辑表达式转变为逻辑树时,parse_logical_expression_impl函数将对逻辑表达式字符串进行递归解析,识别出表达式包含的操作符(and或or)以及Filter信息(ip、roles、app),构造出PolicyLogicalNode并使用左右子节点索引(m_left、m_right)链接起来形成逻辑树并将每个节点存入m_nodes中,最终利用m_nodes构造m_flat_tree数组来模拟二叉树。
m_flat_tree数组的作用是标记逻辑树节点间关系以及标识哪些节点是逻辑树的叶子节点,当用户信息与逻辑树某节点进行匹配时,首先需要与其左右子树进行匹配,然后根据该节点的逻辑运算符来判断是否满足Filter要求,而左右子树的判断结果又依赖于它们的子树的结果,因此这种递归判断方法首先将会是取叶子节点进行用户信息匹配。
openGauss使用“自底向上”的方式来进行用于信息与逻辑树的匹配,从m_flat_tree末尾即叶子节点进行匹配,将匹配结果记录下来,当匹配到非叶子节点时(op节点)只需使用其左右子节点结果进行判断即可,最终实现整个逻辑树的匹配。在例1脱敏策略配置示例中创建脱敏策略后,当用户使用非受限的客户端访问敏感数据时,逻辑树匹配结果如图5所示。

图5 逻辑树匹配示例
在筛选出脱敏策略后,就需要对查询树所有TargetEntry进行识别和策略匹配,从openGauss源码可以看到,支持对SubLink、Aggref、OpExpr、RelabelType、FuncExpr、CoerceViaIO、Var类型的节点进行解析识别。数据脱敏的核心思路是,Var类型节点代表了访问的数据库资源,而非Var类型节点可能包含Var节点,因此需要根据其参数递归的寻找Var节点,最后将识别到的所有Var节点进行策略匹配并根据策略内容进行节点替换。
识别脱敏结点源码:
static bool mask_expr_node(ParseState *pstate, Expr*& expr,const policy_set *policy_ids, masking_result *result, List* rtable, bool can_mask){if (expr == NULL) {return false;}switch (nodeTag(expr)) {case T_SubLink:... // 解析SubLink结点case T_FuncExpr:... // 解析FuncExpr结点case T_Var:return handle_masking_node(pstate, expr, policy_ids, result, rtable, can_mask); // 进入最后脱敏处理过程break;case T_RelabelType:... // 解析RelabelType结点case T_CoerceViaIO:... // 解析CoerceViaIO结点case T_Aggref:... // 解析Aggref结点case T_OpExpr:... // 解析OpExpr结点default:break;}return false;}
在匹配脱敏策略时,首先需要将识别出的Var节点进行解析,将其转为PolicyLabelItem,该数据结构存储了数据列的全部路径信息,然后将其与已过滤出的脱敏策略集合进行匹配,若某个脱敏策略对应的数据库资源对象与PolicyLabelItem一致,将已匹配到的脱敏策略指定的方式替换该Var节点,相关数据结构如下:数据结构PolicyLabelItem。
struct PolicyLabelItem {...void get_fqdn_value(gs_stl::gs_string *value) const;bool operator < (const PolicyLabelItem& arg) const;bool operator == (const PolicyLabelItem& arg) const;bool empty() const {return strlen(m_column) == 0;}void set_object(const char *obj, int obj_type = 0);void set_object(Oid objid, int obj_type = 0);Oid m_schema; // 数据库资源所属的namespace OidOid m_object; // 数据库资源所属的table Oidchar m_column[256];// 列名int m_obj_type; // 资源类型,数据动态脱敏仅支持对COLUMN生效};
脱敏策略匹配成功后,将会根据策略内容替换包含敏感信息的Var节点,使之外嵌脱敏函数。最后将修改后的查询树返还给解析器继续执行,最终敏感数据将会在脱敏函数的作用下返回,以脱敏的形式返回给客户端。数据动态脱敏中例1脱敏策略配置示例里使用gsql查询敏感数据的步骤(4) 中SELECT语句对应的查询树脱敏前的数据组织结构如图6所示。

图6 脱敏结点替换示例
至此,整个查询树已经完成了脱敏策略的匹配与重写,随后将重新回归查询解析模块并继续执行后续处理,最终系统将返回脱敏后的数据结果。
以上内容从数据动态脱敏方面对高斯数据库的数据保护技术进行了解读,下篇讲从数据透明加密方面继续介绍高斯数据库的数据保护。
相关文章:
数据库高安全—数据保护:数据动态脱敏
书接上文数据库高安全—审计追踪:传统审计&统一审计,从传统审计和统一审计两方面对高斯数据库的审计追踪技术进行解读,本篇将从数据动态脱敏方面对高斯数据库的数据保护技术进行解读。 5.1 数据动态脱敏 数据脱敏,顾名思义就…...
Datawhale 数学建模导论二 2025年2月
第6章 数据处理与拟合模型 本章主要涉及到的知识点有: 数据与大数据Python数据预处理常见的统计分析模型随机过程与随机模拟数据可视化 本章内容涉及到基础的概率论与数理统计理论,如果对这部分内容不熟悉,可以参考相关概率论与数理统计的…...
ArcGIS Enterprise 与 ArcGIS Online 的关系
ArcGIS Enterprise 和 ArcGIS Online 是 Esri 提供的两款核心产品,它们在功能、部署方式和使用场景上存在显著差异,但同时也有一定的联系和互补性。以下是关于这两款产品的详细关系说明: 1. 产品定位与功能 ArcGIS Enterprise 是一款企业级解决方案,支持在组织的基础设施上…...
ASP.NET Core SignalR实践指南
Hub类的生命周期是瞬态的,每次调用集线器的时候都会创建一个新的Hub类实例,因此不要在Hub类中通过属性、成员变量等方式保存状态。如果服务器的压力比较大,建议把ASP.NET Core程序和SignalR服务器端部署到不同服务器上,以免它们互…...
【力扣 - 简单题】88. 合并两个有序数组
题目:88. 合并两个有序数组 - 力扣(LeetCode) 解题: class Solution { public:void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {for (int i m; i < n m; i ){nums1[i] nums2[i -…...
【密评】 | 商用密码应用安全性评估从业人员考核题库(23)
在GM/T0048《智能密码钥匙密码检测规范》中,产品的对称算法性能应满足哪个标准中的要求()。 A.GM/T 0016《智能密码钥匙密码应用接口规范》 B.GM/T 0017《智能密码钥匙密码应用接口数据格式规范》 C.GM/T 0027《智能密码钥匙技术规范》 D.GM/T 0028《密码模块安全技术要求》…...
记录 | WPF基础学习MVVM例子讲解1
目录 前言一、NotificationObject与数据属性创建个类,声明NotificationObject 二、DelegateCommand与命令属性三、View与ViewModel的交互(难点)在ViewModel文件下创建MainWindowViewModel数据和方法绑定资源指定 代码下载四、优势体现代码下载…...
PyTorch 中 `torch.cuda.amp` 相关警告的解决方法
在最近的写代码过程中,遇到了两个与 PyTorch 的混合精度训练相关的警告信息。这里随手记录一下。 警告内容 警告 1: torch.cuda.amp.autocast FutureWarning: torch.cuda.amp.autocast(args...) is deprecated. Please use torch.amp.autocast(cuda, args...) i…...
实验7 路由器之间IPsec VPN配置
实验7 路由器之间IPsec VPN配置 1.实验目的 通过在两台路由器之间配置IPsec VPN连接,掌握IPsec VPN配置方法,加深对IPsec协议的理解。 2.实验内容 (1)按照实验拓扑搭建实验环境。 (2)在路由器R1和R4配置IP…...
Unity中快速制作2D沙雕动画:流程编
Unity中快速制作2D沙雕动画(搞笑/无厘头风格),通过以下方案实现低成本、高成效的开发流程,结合夸张的动作、滑稽的物理效果和魔性音效: 1. 角色与素材设计 核心原则:丑萌即正义,越怪越好&#…...
小白零基础如何搭建CNN
1.卷积层 在PyTorch中针对卷积操作的对象和使用的场景不同,如有1维卷积、2维卷积、 3维卷积与转置卷积(可以简单理解为卷积操作的逆操作),但它们的使用方法比较相似,都可以从torch.nn模块中调用,需要调用的…...
【Java八股文】01-Java基础面试篇
【Java八股文】01-Java基础面试篇 概念Java特点Java为什么跨平台JVM、JDK、JRE关系 面向对象什么是面向对象,什么是封装继承多态?多态体现的方面面向对象设计原则重载重写的区别抽象类和实体类区别Java抽象类和接口的区别抽象类可以被实例化吗 深拷贝浅拷…...
k8s部署logstash
1. 编写logstash.yaml配置文件 --- apiVersion: v1 kind: Service metadata:name: logstash spec:type: ClusterIPclusterIP: Noneports:- name: logstash-tcpport: 5000targetPort: 5000- name: logstash-beatsport: 5044targetPort: 5044- name: logstash-apiport: 9600targ…...
Arcgis/GeoScene API for JavaScript 三维场景底图网格设为透明
项目场景: 有时候加载的地图服务白色区域会露底,导致在三维场景时,露出了三维网格,影响效果,自此,我们需要将三维场景的底图设为白色或透明。 问题描述 如图所示: 解决方案: 提示…...
《qt open3d网格拉普拉斯平滑》
qt open3d网格拉普拉斯平滑 效果展示二、流程三、代码效果展示 二、流程 创建动作,链接到槽函数,并把动作放置菜单栏 参照前文 三、代码 1、槽函数实现 void on_actionFilterLaplacian_triggered();void MainWindow::on_actionFil...
怎么选择免费的SEO排名工具
随着2025年互联网的迅猛发展,越来越多的企业意识到,拥有一个高排名的网站对于品牌曝光和吸引客户至关重要。尤其是通过SEO(搜索引擎优化),可以提高网站在搜索引擎中的排名,进而带来更多的自然流量ÿ…...
缓存技术介绍
缓存技术是一种用于提高数据访问速度的技术,通过在快速存储介质(如内存)中保存频繁访问的数据,从而减少对较慢存储介质(如硬盘)的访问次数。缓存可以显著提高系统性能,尤其是在处理大量数据或进…...
SSH隧道+Nginx:绿色通道详解(SSH Tunnel+nginx: Green Channel Detailed Explanation)
SSH隧道Nginx:内网资源访问的绿色通道 问题背景 模拟生产环境,使用两层Nginx做反向代理,请求公网IP来访问内网服务器的网站。通过ssh隧道反向代理来实现,重点分析一下nginx反代的基础配置。 实验环境 1、启动内网服务器的tomca…...
Spring 项目接入 DeepSeek,分享两种超简单的方式!
⭐自荐一个非常不错的开源 Java 面试指南:JavaGuide (Github 收获148k Star)。这是我在大三开始准备秋招面试的时候创建的,目前已经持续维护 6 年多了,累计提交了 5600 commit ,共有 550 多位贡献者共同参与…...
【c++】四种类型转换形式
【c】四种类型转换形式 编译时: static_cast(静态转换) const_cast(去常性转换) reinterpret_cast(重新解释转换,直接转换地址) 运行时: dynamic_cast(动态转换,运行时类…...
Unity 制作2D动画必要准备:启动篇
制作Unity 2D动画需要准备以下内容: 美术素材准备 选择或绘制符合需求的2D精灵图(如像素风格角色、场景元素)确保素材包含完整动画序列帧(如行走/攻击/跳跃等动作分解)注意素材尺寸统一性,建议采用网格化排…...
半小时在本地部署DeepSeek的Janus Pro,进行图片分析和文生图
半小时在本地部署DeepSeek的Janus Pro,进行图片分析和文生图 下载Janus Pro源代码下载模型文件创建Python虚拟环境安装依赖包Janus Pro测试运行程序图片分析测试文生图测试使用中文提示词使用英文提示词 测试印象: 整体模型体积较小,个人可以…...
急停信号的含义
前言: 大家好,我是上位机马工,硕士毕业4年年入40万,目前在一家自动化公司担任软件经理,从事C#上位机软件开发8年以上!我们在开发C#的运动控制程序的时候,一个必要的步骤就是确认设备按钮的急停…...
设置mysql的主从复制模式
mysql设置主从复制模式似乎很容易,关键在于1)主库启用二进制日志,2)从库将主库设为主库。另外,主从复制,复制些什么?从我现在获得的还很少的经验来看,复制的内容有表,用户…...
三角拓扑聚合优化器TTAO-Transformer-BiLSTM多变量回归预测(Maltab)
三角拓扑聚合优化器TTAO-Transformer-BiLSTM多变量回归预测(Maltab) 完整代码私信回复三角拓扑聚合优化器TTAO-Transformer-BiLSTM多变量回归预测(Maltab) 一、引言 1、研究背景和意义 在现代数据科学领域,时间序列…...
东方财富Android面试题及参考答案
接口和抽象类的区别是什么? 定义与语法 接口:接口是一种抽象类型,它只包含方法签名、常量定义,方法默认是public、abstract的,常量默认是public、static、final的。接口不能包含实例变量和普通方法的实现。抽象类:抽象类是一种不能被实例化的类,它可以包含抽象方法和具体…...
ArcGIS基础知识之ArcMap基础设置——ArcMap选项:常规选项卡设置及作用
作为一名 GIS 从业者,ArcMap 是我们日常工作中不可或缺的工具。对于初学者来说,掌握 ArcMap 的基础设置是迈向 GIS 分析与制图的第一步。今天,就让我们一起深入了解 ArcMap 选项中常规选项卡的各个设置,帮助大家更好地使用这款强大的软件。 在 ArcMap 中,常规选项卡是用户…...
element-ui时间组件同一个月内选择/30天内选择
element-ui时间组件同一个月内选择/30天内选择 同一个月 <el-date-picker v-model"time" type"datetimerange"range-separator"至" start-placeholder"开始时间"value-format"timestamp" :picker-options"pickerO…...
Linux Media 子系统 V4l2
一 创建 V4l2 的 entity 在Linux内核的Media Controller框架中,V4L2设备作为实体(entity)的注册过程涉及以下步骤: 1. 初始化Media Controller结构 驱动首先创建一个media_device实例,并与V4L2设备(如v4…...
14,.左下角的值,路径和,由序列确定树
找树左下角的值 迭代法 层序遍历 class Solution { public:int findBottomLeftValue(TreeNode* root) {queue<TreeNode*> qu;qu.push(root);TreeNode* leftqu.front();while(!qu.empty()){int szqu.size();leftqu.front();for(int i0;i<sz;i){TreeNode* curqu.fron…...
