普通用户默认不能查DBA_*视图,授予SELECT ANY DICTIONARY或SELECT_CATALOG_ROLE即开放全部数据字典访问,含密码哈希、审计日志等敏感信息;限制核心在于权限收口而非参数开关,需优先核查并撤销高危授权,禁用o7_dictionary_accessibility仅作辅助,推荐细粒度对象授权替代宽泛角色。
普通用户默认不能查 dba_* 视图,但一旦被授予 select any dictionary 或 select_catalog_role,就等于打开了整个数据字典的门——包括密码哈希、审计日志、加密密钥等敏感信息。限制的关键不是“怎么关”,而是“从哪开始收口”。
确认用户是否已获得高危字典权限
先查清楚现状,避免误操作:
-
SELECT ANY DICTIONARY是系统权限,直接查DBA_SYS_PRIVS:SELECT grantee, privilege FROM dba_sys_privs WHERE privilege = 'SELECT ANY DICTIONARY';
-
SELECT_CATALOG_ROLE是角色,查DBA_ROLE_PRIVS:SELECT grantee, granted_role FROM dba_role_privs WHERE granted_role = 'SELECT_CATALOG_ROLE';
- 注意:
PUBLIC也可能被意外授权,务必检查grantee = 'PUBLIC'的记录
撤销 SELECT ANY DICTIONARY 权限
这是最直接有效的限制手段,但需满足前提:
- 执行者必须是
SYS AS SYSDBA,或拥有GRANT ANY PRIVILEGE的用户 - 命令不带
WITH ADMIN OPTION(该选项在撤销时无效,且本就不该授予) - 语法严格为:
REVOKE SELECT ANY DICTIONARY FROM <username>;
- 撤销后,用户再查
DBA_USERS等视图会立刻报ORA-00942: table or view does not exist,不是视图没了,是权限没了
禁用 o7_dictionary_accessibility 参数
这个参数控制“普通用户能否靠 SELECT ANY TABLE 间接访问字典视图”,属于底层开关:
- 值必须为布尔型:
ALTER SYSTEM SET o7_dictionary_accessibility = false SCOPE=SPFILE; -
SCOPE=SPFILE是硬性要求,MEMORY会报错;改完必须重启数据库才生效 - 设为
false后,即使用户有SELECT ANY TABLE,也无法查SYS.DBA_TABLES这类基表级访问 - 注意:12c 及以后版本中该参数已标记为 deprecated,但仍在生效;新环境建议优先靠权限模型控制,而非依赖此参数
用细粒度授权替代角色/系统权限
如果用户确实需要查部分字典信息(比如巡检脚本要读 V$SESSION),不要给大权限,只给最小所需:
- 对动态性能视图(
V$*),必须授SELECT ON SYS.V_$SESSION,不是V$SESSION(后者是同义词) - 对数据字典视图(如
ALL_TAB_COLUMNS),可直接:GRANT SELECT ON SYS.ALL_TAB_COLUMNS TO <username>;
- 避免授
SELECT_CATALOG_ROLE:它在 12cR2+ 中已被官方标注为 legacy,且隐式激活方式(SET ROLE)容易被忽略导致权限失效 - 验证是否生效:用目标用户连接后执行
SELECT COUNT(*) FROM v_$session;,成功即说明细粒度授权到位
真正难控的不是命令怎么写,而是权限扩散路径——比如 SELECT ANY DICTIONARY 被授予某个中间角色,再由该角色转授给多个用户;这种嵌套授权链必须用 DBA_ROLE_PRIVS 和 ROLE_ROLE_PRIVS 逐层追溯,否则删了表面权限也拦不住实际访问。


















