真正起作用的是REVOKE和GRANT的组合动作而非视图本身;必须显式列字段禁用SELECT*,脱敏逻辑写死在SELECT列表并用IFNULL兜底空值,且需SQL SECURITY DEFINER保障执行上下文安全。

只建视图不撤基表权限,等于没锁门——真正起作用的是 REVOKE 和 GRANT 的组合动作,不是视图本身。
CREATE VIEW 必须显式写字段,禁用 SELECT *
用 SELECT * 创建视图会把基表所有列(包括后续新增的 password_hash、id_card)全暴露出去,元数据里直接可见字段名和类型。
- 正确写法:
CREATE VIEW user_safe AS SELECT id, name, email, created_at FROM users; - MySQL 中基表加新列后,
SELECT *视图会自动包含它;显式列表则完全免疫 - PostgreSQL 要求含表达式时必须声明别名,例如:
SELECT CONCAT(LEFT(phone, 3), '****', RIGHT(phone, 4)) AS phone_masked
脱敏逻辑必须写死在 SELECT 列表里,不能靠应用层补
视图是静态查询定义,不支持参数或运行时判断。脱敏必须用确定性函数拼接,且对空值、空格、长度异常有兜底。
- 手机号推荐:
CONCAT(LEFT(TRIM(phone), 3), '****', RIGHT(TRIM(phone), 4)),再包一层IFNULL(..., '') - 身份证号注意末位 X:
CONCAT(LEFT(id_card, 6), REPEAT('*', 8), RIGHT(TRIM(id_card), 4)) - 禁止用
CURRENT_USER()或NOW()—— MySQL 会报ERROR 1351,或导致策略失效 - BIGINT 类型手机号需先
CAST(phone AS CHAR)再切片,否则LEFT(phone, 3)按数字截取结果不可控
权限必须成对执行:先 REVOKE 基表,再 GRANT 视图
MySQL 权限是白名单制,但旧权限不会自动过期。用户只要还有 SELECT ON mydb.users,就能绕过视图直查明文。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 先查现状:
SHOW GRANTS FOR 'app_user'@'%';,确认没有ON mydb.users或宽泛的ON mydb.* - 显式回收:
REVOKE SELECT ON mydb.users FROM 'app_user'@'%'; - 只授视图:
GRANT SELECT ON mydb.user_safe TO 'app_user'@'%'; - PostgreSQL 额外要:
REVOKE USAGE ON SCHEMA public FROM app_user;,防public.users显式引用绕过
SQL SECURITY DEFINER 是硬性要求,别用默认 INVOKER
默认 SQL SECURITY INVOKER 会让视图以调用者身份执行,如果用户有其他高权限表访问权,可能通过子查询或 JOIN 窃取数据。
- 创建时必须声明:
CREATE SQL SECURITY DEFINER VIEW user_safe AS SELECT ...; -
DEFINER用户(如'dba'@'localhost')需有基表SELECT权限,但该账号本身不应开放给应用 - 别在视图中用非确定性函数(如
RAND()、UUID()),MySQL 会拒绝创建或拒绝缓存执行计划
最容易被忽略的是:脱敏字段无法索引,高频检索仍得依赖原始列;而每个字符串函数一旦遇到 NULL 就整列变空,所以 IFNULL 不是可选项,是必选项。










