前言
上周有个朋友问我:“哥,我们刚从 MySQL 8.0 迁到金仓数据库的 MySQL 兼容模式,发现一个很神奇的 BUG”!
当我在金仓数据库中新建了一个用户以及表,没有对这个用户授权该表的访问权限,但是可以在 sys_class 表中查询到这个表的信息。

也就是说,即使用户没有表的访问权限,也能从系统表(sys_class)查询到该表的存在和元数据信息,这是金仓数据库的 BUG 还是 MySQL 原来就存在这种问题呢?
其实,这既不是金仓的 BUG,也不是 MySQL 的 BUG,而是一个长期存在的数据库安全设计问题。 值得一提的是,金仓数据库在近期将会发布一个新的功能插件 security_utils,针对这个问题进行修复,避免元数据的泄露问题,也是对 MySQL 兼容模式的安全增强!
我这里也是申请到了内测版的安装包,本文将演示一下如何使用 security_utils 插件进行用户的权限隔离,避免元数据泄露!
MySQL 数据库
MySQL 数据库确实存在元数据泄露的问题:
-- 即使用户没有权限,也能查询到表的存在
mysql> SELECT table_name FROM information_schema.tables
WHERE table_schema = 'mydb';
+------------+
| table_name |
+------------+
| orders |
| customers |
| salaries | -- 工资表,敏感!
+------------+
这是 MySQL 的默认设计,不是 BUG,但确实是安全隐患。从 MySQL 5.x 版本到 MySQL 8.0+ 版本都有相关的改进:
| 版本 | 行为 |
|---|---|
| MySQL 5.x | 所有用户可查看所有数据库的表结构 |
| MySQL 8.0+ | 引入部分隔离,但仍可探测表存在性 |
但注意:即使 MySQL 8.0,默认仍可通过 SHOW TABLES 或 information_schema 查看未授权表的名称。
金仓数据库
正如开头的朋友所说,金仓数据库也是存在这种设计问题,下面我用一个例子进行还原。
首先,创建一个表以及用户:
kingbase=# CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
amount DECIMAL(10,2),
order_date DATE);
kingbase=# INSERT INTO orders VALUES
(1, 1001, 5999.00, '2024-11-01'),
(2, 1002, 3299.00, '2024-11-15');
kingbase=# CREATE USER finance with password 'Finance@123';
切换到 finance 用户查询:
kingbase=# \c - finance
用户 finance 的口令:
您现在以用户名"finance"连接到数据库"kingbase"。
kingbase=> select oid,relname from sys_class where relname='orders';
oid | relname
-------+---------
16644 | orders
kingbase=> select * from orders;
ERROR: permission denied for table orders
kingbase=> \dt
关联列表
架构模式 | 名称 | 类型 | 拥有者
----------+--------+--------+--------
public | orders | 数据表 | system
kingbase=> \d orders
数据表 "public.orders"
栏位 | 类型 | 校对规则 | 可空的 | 预设
-------------+---------------+----------+----------+------
order_id | integer | | not null |
customer_id | integer | | |
amount | numeric(10,2) | | |
order_date | date | | |
索引:
"orders_pkey" PRIMARY KEY, btree (order_id NULLS FIRST)
可以发现,此时 finance 用户并没有表 orders 的访问权限,但是仍然可以通过 sys_class 查看到 orders 表的元数据,甚至是表结构,这是十分不安全。
加载插件
金仓数据库提供用户权限隔离功能,用户权限隔离功能开启后,普通用户只能查看有权访问的对象(表、函数、视图、字段等)。
用户权限隔离功能开启需要加载插件 security_utils,在使用 security_utils 之前,我们需要将他添加到 kingbase.conf 文件的 shared_preload_libraries 中,并重启 KingbaseES 数据库:
shared_preload_libraries = 'security_utils'

重启数据库生效:
[kingbase@kesv9:/install]$ sys_ctl restart -D /data/
等待服务器进程关闭 .... 完成
服务器进程已经关闭
等待服务器进程启动 ....2025-08-27 00:08:29.862 CST [93180] LOG: config the real archive_command string as soon as possible to archive WAL files
2025-08-27 00:08:29.869 CST [93180] LOG: sepapower extension initialized
2025-08-27 00:08:29.903 CST [93180] LOG: starting KingbaseES V009R003C012
2025-08-27 00:08:29.903 CST [93180] LOG: listening on IPv4 address "0.0.0.0", port 54321
2025-08-27 00:08:29.903 CST [93180] LOG: listening on IPv6 address "::", port 54321
2025-08-27 00:08:29.905 CST [93180] LOG: listening on Unix socket "/tmp/.s.KINGBASE.54321"
2025-08-27 00:08:29.986 CST [93180] LOG: redirecting log output to logging collector process
2025-08-27 00:08:29.986 CST [93180] HINT: Future log output will appear in directory "sys_log".
完成
服务器进程已经启动
开启权限隔离功能:
kingbase=# \c - system
您现在以用户名"system"连接到数据库"kingbase"。
-- 开启功能
kingbase=# create extension kdb_schedule;
CREATE EXTENSION
kingbase=# create extension security_utils;
CREATE EXTENSION
至此,用户隔离的插件已开启。
实战演示
接下来,演示一下 Kingbase MySQL 兼容模式如何进行用户权限隔离。
数据库级别开启用户权限隔离:
kingbase=> \c - system
用户 system 的口令:
您现在以用户名"system"连接到数据库"kingbase"。
kingbase=# alter database kingbase enable object isolation;
ALTER DATABASE
再切换到 finance 用户查询:
kingbase=# \c - finance
用户 finance 的口令:
您现在以用户名"finance"连接到数据库"kingbase"。
kingbase=> select oid,relname from sys_class where relname='orders';
oid | relname
-----+---------
(0 行记录)
kingbase=> \dt
Did not find any relations.
kingbase=> \d orders
Did not find any relation named "orders".
已经无法查询到 sys_class 中 orders 表的信息,包括元数据以及表结构,都已经无法查看。
如果想要访问以上元数据,则需要人为进行授权该表给用户才行:
kingbase=> \c - system
用户 system 的口令:
您现在以用户名"system"连接到数据库"kingbase"。
kingbase=# grant select on table orders to finance;
GRANT
再切换到 finance 用户查询:
kingbase=# \c - finance
用户 finance 的口令:
您现在以用户名"finance"连接到数据库"kingbase"。
kingbase=> select oid,relname from sys_class where relname='orders';
oid | relname
-------+---------
16644 | orders
(1 行记录)
kingbase=> \dt
关联列表
架构模式 | 名称 | 类型 | 拥有者
----------+--------+--------+--------
public | orders | 数据表 | system
(1 行记录)
kingbase=> \d orders
数据表 "public.orders"
栏位 | 类型 | 校对规则 | 可空的 | 预设
-------------+---------------+----------+----------+------
order_id | integer | | not null |
customer_id | integer | | |
amount | numeric(10,2) | | |
order_date | date | | |
索引:
"orders_pkey" PRIMARY KEY, btree (order_id NULLS FIRST)
可以发现,金仓数据库通过插件方式实现了开关式的一键开关用户权限隔离功能,十分方便快捷。
金仓数据库的这个功能,技术底层实现依赖 行级安全策略(Row-Level Security, RLS),通过修改数据库状态,为当前数据库具有 ACL 字段的系统表统一添加配置好的 RLS,通过 RLS 筛选以实现普通用户只能查看有权访问的对象(表、函数、视图、字段等)的目的。
写在最后
在数字化时代,数据安全至关重要,数据库权限管理是核心保障。金仓数据库通过 security_utils 插件提供了超越 MySQL 原生能力的安全特性,补齐了 Oracle 级别的安全特性,通过插件化实现,兼顾灵活性和安全性。
同时,金仓数据库高度兼容 MySQL 的语法与基本功能,降低应用迁移成本,还在权限管理上实现功能增强,能满足金融、医疗等领域复杂需求,为企业数字化转型提供可靠数据安全支撑。
782

被折叠的 条评论
为什么被折叠?



