编程 KingbaseES 动态脱敏:anon.add_policy 只认表.列,视图配不了、CTAS 会把脱敏值落库

2026-11-02 00:03:57

视图上配不了策略:KingbaseES v9.4.12 动态脱敏落地时踩到的边界

测试环境要接一批外包联调,库里有手机号、金额几列不能给原值。第一版方案很朴素:在基表上建视图,行裁剪、列裁剪都写在视图里,只把视图的 SELECT 权限授给测试账号,一条脱敏策略都不加。推下去第一步就卡住——视图上根本配不了脱敏策略。改成直接在基表上加策略,后面又连着遇到物化视图刷不动、分区表策略加到子分区无效、测试同事用 CTAS 把脱敏后的值固化进自己的中间表。下面按手册条目把这些边界理一遍。

插件与扩展

动态脱敏由 sys_anon 提供,先在 kingbase.conf 里预加载:

shared_preload_libraries = 'sys_anon'

新建的数据库还要单独建扩展:

CREATE EXTENSION sys_anon;

脱敏在 SQL 查询结果返回时才改值,缓存和存储里仍是原值,字段类型和格式不变,所以对应用是透明的;同一个库上的不同连接可以同时处于脱敏和不脱敏状态。

add_policy 的五个参数

add_policy(policy_name text, objname text, username text, func_desc text, para_list text)
  • policy_name:策略名,不可为空,唯一。
  • objname:待脱敏对象,格式 模式.表.列;不写模式时为 表.列,模式默认 public。
  • user_name:待脱敏对象的用户名,可为空,为空表示对所有用户脱敏。
  • func_desc:脱敏函数名,可为空,为空则走默认脱敏。
  • para_list:函数参数列表,目前仅适用于部分脱敏,参数逗号分隔,例如 '2,2'。

三种脱敏函数

默认完整脱敏 default:不指定函数时即为此种。字符类型返回空值;数字类型返回 0(不保证精度);布尔类型返回 f;时间类型年月日部分为 1970-01-01,时分秒为 00:00:00。

test=# CREATE TABLE t1(a int);
test=# \c test sso
test=> SELECT anon.add_policy('pol1', 't1.a', '','','');

部分数据脱敏 partial(prefix int, suffix int):适用于 varchar、char、text。prefix 保留前 n 位,suffix 保留后 n 位,其余位用 * 替换。

SELECT anon.add_policy('pol2','public.t2.a','u1','partial','2,2');

随机数据脱敏:random_string 用于字符类型,变长按实际长度生成随机串,定长按最大长度;random_date 生成 1900-01-01 00:00:00 至今之间的随机时间;random_int 生成 0 至该类型最大值之间的随机整数。

四个容易忽略的细节:

  1. 部分脱敏要保留的位数超过字符串长度时,退化为最基本的部分脱敏:字符串长度为奇数时脱敏最中间的一个字符,偶数时脱敏最中间的两个字符。
  2. 字符串类型脱敏,定长按最大长度算,变长按实际长度算。
  3. 带策略的列改数据类型时,只能改成当前策略支持范围内的类型。
  4. 要让策略对多个用户生效,添加策略时 username 直接置空。

手册条目与现场后果

手册中的说明落到操作上的后果
策略仅允许安全员 sso 配置及查看,其他用户均无权限应用账号、普通 DBA 账号既调不了 anon.add_policy,也看不到已配的策略;建策略、查策略都要换 sso 连接
仅支持普通表、分区表和物化视图,不支持普通视图视图 + 授权这条隔离路线走不通,视图上没法配策略
在脱敏表上建视图后,脱敏用户查询视图得到的是脱敏后的值视图可以继续用来看,但脱敏效果来自基表策略,不是视图本身
策略仅对用户表及物化视图有效,系统表无效系统表上的敏感列不在保护范围
不支持在脱敏表上建立物化视图;已建物化视图的表上装策略,物化视图将无法更新数据先建的物化视图会卡在刷新这一步
仅支持在分区表的主表上配置脱敏策略策略挂主表生效,挂到子分区上不起作用
user_name 为空则对所有用户脱敏空串不是“不脱敏”,是全库连接都脱敏,运维自己查也是脱敏值
partial 保留位超过字符串长度时,奇数长度脱最中间一个字符,偶数长度脱最中间两个短值不会原样返回,也不会报错,只是中间被替换掉
定长按最大长度脱敏,变长按实际长度脱敏char(n) 列即使只存一个字符也按 n 位处理,输出长度与原值对不上
带策略的列修改数据类型,只能改为当前策略支持范围内的类型跨类型改列会被挡住,改表结构前要先清理策略
CTAS 或 INSERT INTO ... SELECT 的数据来源于脱敏数据落盘的就是脱敏后的值,且无法还原
MERGE INTO 的数据来源于脱敏表(无论是否包含脱敏列)均无法更新数据
分区表上存在脱敏策略时交换分区只交换分区数据,不交换脱敏策略
设置了动态脱敏策略的表,需要谨慎授予其他用户 trigger 权限拿到 trigger 权限的用户可以借触发器绕过脱敏
策略可用 sys_dump / sys_restore 备份恢复,需用 sso换普通账号做备份恢复会拿不到策略;升级前先备份脱敏配置,升级后恢复

可复现的验证过程

-- kingbase.conf: shared_preload_libraries = 'sys_anon'
CREATE EXTENSION sys_anon;

-- 建表并写入两条测试数据
CREATE TABLE t2(a varchar(32), b int);
INSERT INTO t2 VALUES ('13800001234', 100), ('abc', 200);

-- 切到安全员 sso,只对 u1 生效,保留前 2 后 2 位
\c test sso
SELECT anon.add_policy('pol2','public.t2.a','u1','partial','2,2');

-- 换被脱敏用户查询
\c test u1
SELECT * FROM t2;

-- 对照:sso 自己查仍然是原值
\c test sso
SELECT * FROM t2;

按规则推出来的结果:13800001234 共 11 位,保留前 2 后 2,中间 7 位被替换,得到 13*******34;abc 只有 3 位,保留位超过长度,走奇数长度的回退规则,脱掉最中间一个字符,得到 a*c。

要验证 username 置空的效果,换一列再加一条策略,此时所有连接看到的都是默认脱敏值:

SELECT anon.add_policy('pol_all','public.t2.b','','','');

策略的备份恢复同样要 sso 身份:

./sys_dump -d test -p 54321 -U sso -W -F c -f anon.dmp
./sys_restore -p 54321 -U sso -W -d test anon.dmp

排查顺序

  1. shared_preload_libraries 里有没有 sys_anon,目标库有没有执行过 CREATE EXTENSION sys_anon。
  2. 当前连接是不是 sso。非 sso 连策略都看不见,先排除这一层再谈其他。
  3. 看对象类型:普通表、分区表主表、物化视图可以配;普通视图、系统表不行。
  4. 看 user_name 参数是不是空串。空串等于全用户脱敏,经常被当成关闭开关。
  5. 用 sso 和目标用户各查一次同一张表,确认差异是策略产生还是别处的视图/中间表带来的。
  6. partial 结果不对时,先量字符串实际长度,再确认列是定长还是变长。
  7. 检查脱敏表上是否已经存在物化视图、是否把 trigger 权限授了出去、下游有没有 CTAS 或 MERGE INTO 作业。
  8. 备份恢复与升级流程里,确认 sys_dump / sys_restore 用的是 sso,升级前后的脱敏配置备份恢复都跑过。

文档链接:https://bbs.kingbase.com.cn/kingbase-doc/v9.4.12/safety/safety-guide/data-redaction.html

推荐文章

程序员茄子在线接单