视图中不选敏感字段即可隐藏它们,即创建视图时必须显式列出非敏感列、禁用select *,并配合撤销基表权限与授予视图权限,才能确保敏感字段对用户完全不可见。

视图里不选敏感字段,就能隐藏它们
只要在创建视图的 SELECT 语句中**完全不包含**密码、身份证号、手机号等敏感列,这些列对视图使用者就是不可见的。数据库不会因为基表存在某列就自动暴露它——视图只暴露你明确写出的列。
常见错误是误以为加了 WHERE 条件或用了 GRANT SELECT ON view_name 就能控制列级权限,其实没用:如果视图定义里写了 SELECT * 或显式包含了 user_password,那授权给用户查视图,等于直接把敏感字段交出去。
- 永远避免在视图定义中使用
SELECT *,必须手写所需列名 - 敏感字段如
id_card、salary、email等,不出现在视图SELECT列表里,就真的查不到 - 即使用户有基表的
SELECT权限,只要他只能访问视图,就无法绕过这个限制(前提是不给他查基表的权限)
CREATE VIEW 时用别名和计算列进一步脱敏
仅“不选”还不够,有时需要主动变形。比如展示员工信息时,可以只暴露邮箱域名、工资范围,而不是原始值。
示例:
CREATE VIEW emp_public AS
SELECT id, name,
SUBSTRING_INDEX(email, '@', -1) AS email_domain,
CASE WHEN salary > 5000 THEN 'high' ELSE 'mid' END AS salary_level
FROM employees;
-
SUBSTRING_INDEX()是 MySQL 函数;PostgreSQL 用SPLIT_PART(email, '@', 2);SQL Server 用RIGHT(email, CHARINDEX('@', REVERSE(email)) - 1) - 别名(如
email_domain)会覆盖原始列名,防止通过元数据反推原字段 - 计算列无法被
UPDATE或INSERT(除非定义为可更新视图且满足条件),天然只读更安全
注意视图是否可更新,避免意外修改基表
如果视图只含单表、无聚合、无去重、无表达式,部分数据库允许通过视图执行 UPDATE 或 INSERT——但这可能绕过你的列过滤逻辑,让敏感字段被间接写入。
例如:一个视图漏掉了 is_deleted 列,但用户通过视图 UPDATE 其他字段时,可能无意中把已软删除的记录“复活”。
- MySQL 默认允许简单视图更新;PostgreSQL 要求视图定义为
WITH CHECK OPTION才可控 - 如无需写入,显式加
WITH READ ONLY(Oracle/PostgreSQL 支持)或干脆不授INSERT/UPDATE权限 - 检查视图是否可更新:PostgreSQL 查
pg_views.definition,MySQL 看information_schema.VIEWS.IS_UPDATABLE
权限链路上最容易被忽略的一环:基表权限残留
即使视图定义干净、权限授予精准,只要用户还保留对源表的 SELECT 权限,就能绕过视图直接查基表——所有列都会暴露。
所以,视图不是权限开关,只是权限代理层。真正起作用的是“撤销基表权限 + 授予视图权限”这个组合动作。
- 执行
REVOKE SELECT ON employees FROM app_user;必须做,不能只做GRANT SELECT ON emp_public TO app_user; - 注意角色继承:如果
app_user属于dev_role,而dev_role有基表权限,那撤销仍无效 - 定期审计:查询
information_schema.ROLE_TABLE_GRANTS或pg_roles配合pg_class,确认无隐式权限残留
视图本身不加密、不拦截、不审计,它只是 SQL 语句的预定义快照。列是否可见,取决于你写没写它;数据是否安全,取决于你有没有关掉其他所有入口。










