视图本身不控制列权限,仅投影显式指定的列;真正实现列级控制需配合回收基表权限并单独授予视图select权限,缺一不可。

视图里漏写敏感列 ≠ 列权限被控制
显式写 SELECT id, name, status FROM users 确实让查询视图时看不到 salary 或 ssn,但这只是“看不见”,不是“不能看”。只要用户有基表的 SELECT 权限,执行 SELECT salary FROM users 就立刻暴露。
- PostgreSQL 中报错
permission denied for relation users,往往是因为忘了REVOKE SELECT ON users FROM app_user - MySQL 8.0+ 用户若被授予
SELECT ON mydb.users,哪怕你建了user_safe_view,也完全无效 - SQL Server 视图定义不会自动同步基表结构变更;新增列后若没重编译
ALTER VIEW,可能因列数不匹配导致查询失败
GRANT SELECT(col1, col2) 比视图更底层,但有版本和操作限制
MySQL 8.0+ 和 SQL Server 支持直接按列授 SELECT 权限,例如:
GRANT SELECT (user_id, username) ON users TO 'reporter'@'%';
但这不等于“安全隔离”:
- 语法必须严格:
GRANT SELECT ON users(user_id, username)是错的,括号必须在列名前 - 列权限和表权限叠加生效:如果用户已有整表
SELECT,再授部分列不会撤销其他列访问权 - MySQL 5.7 及更早版本不支持该语法,执行会直接报
ERROR 1064 - UPDATE 列权限下,用户仍可执行
UPDATE t SET phone = phone(空更新),虽不能设新值,但可能触发审计或触发器
视图 + SECURITY DEFINER 才能绕过调用者权限检查
默认情况下,PostgreSQL 视图走 SECURITY INVOKER(调用者权限),MySQL 视图默认以 DEFINER 身份执行——但若 DEFINER 账号不存在或权限不足,会报 ERROR 1449。
- PostgreSQL 需显式加
CREATE VIEW ... WITH (security_invoker = false)或后续ALTER VIEW ... SET (security_invoker = false) - MySQL 必须确保
DEFINER是高权限账号(如'root'@'localhost'),且该账号真实存在、未被删除 - SQL Server 中用
SCHEMABINDING创建视图可防止基表结构被随意修改,但不增强权限隔离能力
脱敏表达式会让索引失效,别在视图里套函数
在视图里写 MD5(email)、SUBSTRING(phone, 1, 3) 或 CASE WHEN dept='HR' THEN salary ELSE NULL END,看似隐藏了数据,实际代价很大:
- 这些字段在视图中已不是原始列,
WHERE email = ?无法命中email索引,变成全表扫描 - PostgreSQL 的
pg_get_viewdef()、MySQL 的SHOW CREATE VIEW可让有视图查看权限的用户直接看到脱敏逻辑 - 若脱敏依赖前端传参(如
CASE WHEN ? = 'HR' THEN salary...),极易被注入或绕过
CREATE VIEW 这一行语句,而是紧随其后的那几条 REVOKE 和 GRANT。漏掉任何一条,前面所有视图设计都形同虚设。











