MySQL不支持列级权限,需用视图实现字段脱敏:显式列出非敏感列并处理敏感字段,禁用上下文函数与拼接操作,授视图权限前必须回收基表权限,并通过存储函数+SQL SECURITY DEFINER实现动态脱敏。

MySQL中无法直接按列限制权限,得用视图绕过
MySQL原生的GRANT语句不支持“只给某张表的某些列授权”,SELECT权限最小粒度是整张表。想让开发账号看不到password_hash、id_card这类字段,必须换思路:用视图封装脱敏逻辑,再对视图单独授权。
创建安全视图时要避开NULL和函数陷阱
视图里不能直接暴露敏感字段,但也不能简单写SELECT * EXCEPT password_hash——MySQL不支持这种语法。得显式列出非敏感列,并对敏感字段做处理:
CREATE VIEW user_safe_view AS
SELECT id, username, email,
'***' AS password_hash,
CASE WHEN is_dev = 1 THEN 'DEV' ELSE 'PROD' END AS env_label
FROM users;
注意三点:
- 别在视图里调用
NOW()或USER()等上下文函数,否则权限校验可能绕过 - 避免用
CONCAT()拼接敏感字段(比如CONCAT('x', password_hash)),攻击者仍可能反推原始值 - 如果原表有
TEXT或JSON字段含敏感内容,必须显式过滤或CAST(... AS CHAR(0))清空
给开发账号授视图权限前先回收基表权限
这是最容易漏的一步。即使你只GRANT SELECT ON mydb.user_safe_view TO 'dev_user'@'%',如果之前没 revoke 基表权限,对方仍能直接查users表。
务必执行:
REVOKE SELECT ON mydb.users FROM 'dev_user'@'%'; GRANT SELECT ON mydb.user_safe_view TO 'dev_user'@'%';
验证是否生效:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
用dev_user登录后执行SELECT * FROM users;应报错ERROR 1142 (42000): SELECT command denied to user;而SELECT * FROM user_safe_view;能正常返回。
敏感列动态脱敏需用存储函数+SQL SECURITY DEFINER
如果需要根据登录用户身份动态控制列可见性(比如DBA能看到完整手机号,开发只能看138****1234),就得用存储函数:
DELIMITER $$
CREATE FUNCTION mask_phone(p VARCHAR(20))
RETURNS VARCHAR(20)
SQL SECURITY DEFINER
READS SQL DATA
BEGIN
IF CURRENT_USER() LIKE 'dba@%' THEN
RETURN p;
ELSE
RETURN CONCAT(LEFT(p,3), '****', RIGHT(p,4));
END IF;
END$$
DELIMITER ;
关键点:
-
SQL SECURITY DEFINER确保函数以定义者权限运行,否则CURRENT_USER()会返回调用者身份,失去控制力 - 函数必须声明
READS SQL DATA,否则在视图里调用会报错 - 别把函数逻辑写进视图定义里——视图一旦创建,函数变更不会自动同步,得
DROP VIEW再重建
真正难的是权限链路的完整性:视图依赖函数,函数依赖基表,基表权限又得彻底切断。少一个环节,敏感数据就可能裸奔。










