视图安全需三层控制:定义层必须显式列字段禁用SELECT*,权限层须单独授予视图SELECT权限,元数据层须限制INFORMATION_SCHEMA等系统表访问,缺一不可。

视图本身不自动隐藏敏感列,必须显式写字段名;权限不继承基表,必须单独授予视图——这两点没做到,视图就等于没设防。
视图定义必须显式列出字段,禁用 *
用 SELECT * 创建视图是列级泄露的起点。哪怕基表只新增一列 password_hash,视图立刻暴露它,且用户查 SELECT * FROM my_view 就能拿到。
- 正确写法:
SELECT user_id, username, created_at FROM users - 错误写法:
SELECT * FROM users(开发省事,上线后出事) - MySQL 8.0+ 和 PostgreSQL 都支持该写法,但 SQL Server 视图不会随基表自动更新,改了基表结构后必须手动
ALTER VIEW,否则可能报错或返回空值
视图权限必须显式 GRANT SELECT,不能依赖基表权限
用户有基表 SELECT 权限 ≠ 能查视图;用户没基表权限 ≠ 不能查视图——视图权限独立生效。
- MySQL 授权:执行
GRANT SELECT ON my_user_view TO 'analyst'@'%' - PostgreSQL 授权:执行
GRANT SELECT ON my_user_view TO analyst - 常见错误:只授了
users表权限,忘了给视图授权,结果报permission denied for relation users(PostgreSQL)或类似拒绝提示 - PostgreSQL 默认走
SECURITY INVOKER,若想让视图以创建者身份执行(绕过调用者对基表的权限检查),需显式设置CREATE VIEW ... WITH (security_invoker = false)或建完用ALTER VIEW ... SET (security_invoker = false)
别让视图定义本身变成信息源
攻击者只要能查 INFORMATION_SCHEMA.VIEWS 或 pg_get_viewdef(),就能看到视图里写了哪些字段、用了什么 CASE WHEN 脱敏逻辑,甚至反推出敏感字段名。
- MySQL:执行
REVOKE SELECT ON INFORMATION_SCHEMA.VIEWS FROM 'app_user'@'%'(该权限默认开放) - PostgreSQL:执行
REVOKE SELECT ON pg_views FROM app_user,并确保app_user不在pg_read_all_data角色中 - 生产环境禁用
SHOW CREATE VIEW权限,哪怕账号只有SELECT—— 这个命令会直接返回完整定义 - 视图里用函数做脱敏?小心函数体可被查(如
pg_get_functiondef()),更隐蔽的风险是函数内部又查了别的配置表
元数据访问必须掐断,否则视图再严也白搭
只要用户能查 INFORMATION_SCHEMA.TABLES 或 pg_tables,就能枚举出所有表、所有列,然后针对性地构造查询绕过视图限制。
- MySQL 8.0.29+:在
my.cnf加skip-show-databases,让非 super 用户执行SHOW DATABASES返回空 - PostgreSQL:执行
REVOKE USAGE ON SCHEMA pg_catalog FROM app_user(关键一步,否则SELECT * FROM pg_catalog.pg_tables仍可执行) - SQL Server:避免误授
VIEW DEFINITION权限,普通账号不应属于db_owner或sysadmin - 注意:回收
information_schema权限在 MySQL 中需显式REVOKE,但部分旧版本不生效,得靠关闭元数据访问开关兜底
最易被忽略的是:视图安全不是“建完就完”,它依赖三层控制——定义层(字段显式写)、权限层(视图单独授权)、元数据层(堵死 schema 查询)。少一层,攻击者就能从视图外打穿进来。

















