应查询DBA_SYS_PRIVS和DBA_ROLE_PRIVS视图确认SELECT ANY DICTIONARY及SELECT_CATALOG_ROLE授权情况,重点检查PUBLIC授予权限、角色嵌套链及O7_DICTIONARY_ACCESSIBILITY参数是否为TRUE,三者任一存在均可能导致数据字典被间接访问。
查 SELECT ANY DICTIONARY 授权情况
这个系统权限是打开数据字典大门的“万能钥匙”,一旦授予,用户就能查 dba_users、dba_tables 等所有 dba_* 视图,包括密码哈希字段(旧版本)和审计配置。直接查授权记录最可靠:
- 用
SYS AS SYSDBA连接后执行:SELECT grantee, privilege FROM dba_sys_privs WHERE privilege = 'SELECT ANY DICTIONARY'; - 务必检查
grantee = 'PUBLIC'的结果——这是最容易被忽略的全局放权点 - 注意:
GRANTEE字段可能是用户名,也可能是角色名;若为角色,需进一步查DBA_ROLE_PRIVS确认谁被授了该角色
查 SELECT_CATALOG_ROLE 分配情况
这个预定义角色比 SELECT ANY DICTIONARY 限制稍多,但依然覆盖大量敏感视图(如 DBA_AUDIT_TRAIL、DBA_REGISTRY),且常被误当作“安全替代”。它不走系统权限路径,而是角色链:
- 执行:
SELECT grantee, granted_role FROM dba_role_privs WHERE granted_role = 'SELECT_CATALOG_ROLE'; - 如果
grantee是角色(比如MONITOR_ROLE),得再查该角色是否又被授给其他用户 - 12c 及以后版本中,该角色已标记为 deprecated,但仍在生效;新环境应避免依赖它
查 DBA_* 视图实际可访问用户
有些用户没直接受权,却因拥有 SELECT ANY TABLE + O7_DICTIONARY_ACCESSIBILITY = TRUE 间接获得访问能力。这时不能只看权限表,得验证实际行为:
- 用疑似高权限用户登录,执行:
SELECT COUNT(*) FROM dba_users; - 若返回行数 > 0,说明该用户当前能访问数据字典(无论是否显式授权)
- 此时必须检查数据库参数:
SHOW PARAMETER o7_dictionary_accessibility;若为TRUE,即使没授SELECT ANY DICTIONARY,SELECT ANY TABLE也能穿透字典基表
为什么不能只查 USER_SYS_PRIVS 或 ALL_SYS_PRIVS?
这两个视图对普通用户无效:USER_SYS_PRIVS 只显示当前登录用户的系统权限,ALL_SYS_PRIVS 根本不存在(Oracle 没有这个视图)。想看清全局授权分布,唯一可信入口是 DBA_SYS_PRIVS 和 DBA_ROLE_PRIVS,且必须用具备 SELECT ANY DICTIONARY 或 DBA 角色的账号查询。
真正容易被绕过的不是权限本身,而是 PUBLIC 授权、角色嵌套、以及 o7_dictionary_accessibility 参数的隐式放行——这三处不清理干净,光 revoke 单个用户权限只是表面功夫。











