Appearance
数据脱敏测试覆盖案例
1. 背景与挑战
在 SQL 审计平台中,数据脱敏是核心安全功能之一。市面上不少方案的实现思路是「结果集列名匹配」:
- 执行 SQL 查询。
- 获取结果集的列名(Column Names)。
- 将列名与脱敏规则(如
user_account_id)进行正则匹配。 - 如果匹配,对该列数据进行脱敏处理。
这套思路识别的是「结果列名」,而不是「字段的血缘来源」,因此只要把敏感字段改头换面,就能轻松绕过:
| 绕过手法 | 列名匹配方案 | NextMeta |
|---|---|---|
函数包裹(MD5 / CONCAT / CAST 等) | 可绕过 | 拦截 |
别名(AS xxx) | 可绕过 | 拦截 |
| 子查询 / 多层嵌套 | 可绕过 | 拦截 |
UNION 合并查询 | 可绕过 | 拦截 |
| 大小写变换 | 可能失效 | 拦截 |
NextMeta 采用字段血缘追踪,直接从 SQL 语义层面识别敏感字段的真实来源。下方测试素材覆盖的函数包裹、别名、子查询、CTE、UNION、通配符、注释、大小写、多行换行等全部绕过方式,均已实测拦截。
边界加固(v2.0.5):本轮实测修复了三处可通过字段血缘绕过的边界漏洞——
GROUP_CONCAT等多值拼接聚合:mask_middle只遮中间 1/3,头尾明文泄露,已改为对聚合结果强制mask_all;UNION合并查询:结果列由最左分支决定,已递归分析最左分支的血缘;- 子查询改名 +
SELECT *:外层*展开子查询列,已按子查询输出列顺序传播脱敏规则。另:查询窗口按业务要求只允许
SELECT/EXPLAIN,WITH(CTE)语句在查询窗口被正常拦截,不视为绕过。
sql
-- 以下方式绕过脱敏全部可以安全防护
-- 数据库审核平台脱敏规则测试集
-- 目标表: orders
-- 敏感字段: user_account_id
-- 测试目的: 验证审核逻辑是否能识别经过变形、别名或函数包裹后的敏感字段引用
SELECT user_account_id FROM orders LIMIT 1;
SELECT `user_account_id` FROM `orders` LIMIT 1;
SELECT orders.user_account_id FROM orders LIMIT 1;
SELECT MD5(user_account_id) FROM orders LIMIT 1;
SELECT HEX(user_account_id) FROM orders LIMIT 1;
SELECT TO_BASE64(user_account_id) FROM orders LIMIT 1;
SELECT CONCAT(user_account_id, '_test') FROM orders LIMIT 1;
SELECT CONCAT_WS('-', user_account_id, 'prefix') FROM orders LIMIT 1;
SELECT SUBSTR(user_account_id, 1, 5) FROM orders LIMIT 1;
SELECT LEFT(user_account_id, 5) FROM orders LIMIT 1;
SELECT TRIM(user_account_id) FROM orders LIMIT 1;
SELECT REVERSE(user_account_id) FROM orders LIMIT 1;
SELECT CAST(user_account_id AS CHAR) FROM orders LIMIT 1;
SELECT CONVERT(user_account_id, CHAR) FROM orders LIMIT 1;
SELECT GROUP_CONCAT(user_account_id) FROM orders LIMIT 1;
SELECT MAX(user_account_id) FROM orders;
SELECT CASE WHEN 1=1 THEN user_account_id ELSE '0' END FROM orders LIMIT 1;
SELECT IF(TRUE, user_account_id, 'hidden') FROM orders LIMIT 1;
SELECT COALESCE(NULL, user_account_id) FROM orders LIMIT 1;
SELECT user_account_id + 0 FROM orders LIMIT 1;
SELECT user_account_id * 1 FROM orders LIMIT 1;
SELECT user_account_id AS harmless_id FROM orders LIMIT 1;
SELECT user_account_id "uid" FROM orders LIMIT 1;
SELECT t.safe_col FROM (SELECT user_account_id AS safe_col FROM orders) t LIMIT 1;
SELECT final_col FROM (SELECT temp_col AS final_col FROM (SELECT user_account_id AS temp_col FROM orders) a) b LIMIT 1;
WITH sensitive_data AS (
SELECT user_account_id FROM orders
)
SELECT * FROM sensitive_data LIMIT 1;
SELECT user_account_id/**/ FROM orders LIMIT 1;
SELECT user_account_id /*!50000 */ FROM orders LIMIT 1;
SELECT
user_account_id
FROM
orders
LIMIT 1;
SELECT t.* FROM orders t LIMIT 1;
-- 边界加固用例(v2.0.5 修复后全部拦截)
SELECT user_account_id AS safe_col FROM orders
UNION
SELECT user_account_id AS safe_col FROM orders
LIMIT 1;
SELECT * FROM (SELECT user_account_id AS safe_col FROM orders LIMIT 1) t;