普通用户查dba_users报ora-00942是因缺乏select any dictionary或select_catalog_role权限,而非视图不存在;且11g起password列恒为null,真实哈希存于user$表spare4字段。

普通用户查DBA_USERS报ORA-00942不是视图不存在,是权限没给
Oracle 默认不给任何普通用户访问 DBA_* 视图的权限——哪怕这个用户能连上数据库、能查自己的表、甚至有 SELECT ANY TABLE,只要没被显式授权,执行 SELECT * FROM DBA_USERS 就一定报 ORA-00942: table or view does not exist。这不是 bug,是设计:DBA 视图属于 SYS 模式下的受保护对象,访问控制完全依赖授权体系,不靠“隐藏”或“屏蔽”。
真正起作用的是SELECT ANY DICTIONARY和SELECT_CATALOG_ROLE
能查 DBA_* 视图,只有两条路:
-
SELECT ANY DICTIONARY:系统权限,一授就通杀所有字典视图(含DBA_AUDIT_TRAIL、DBA_ENCRYPTION_KEYS等敏感视图),风险最高 -
SELECT_CATALOG_ROLE:预定义角色,覆盖常用DBA_*和ALL_*视图,但默认不包含密码哈希、审计明细等字段,12c+ 官方倾向用它替代前者
注意:DBA 角色本身不含这两个权限,必须单独授予;SELECT ANY TABLE 也不能穿透字典访问限制——除非 _O7_DICTIONARY_ACCESSIBILITY = TRUE(已弃用,且仅影响 CONNECT 用户启动时行为)。
查不到DBA_USERS.password不是权限问题,是 Oracle 主动清空了该列
从 11g 起,DBA_USERS 视图的 PASSWORD 列始终为 NULL 或空字符串,这是 Oracle 的安全加固逻辑,与你有没有 SELECT ANY DICTIONARY 无关。真实哈希存在底层 user$ 表的 spare4 字段里,但:
- 查
user$需要SELECT ANY DICTIONARY,且该表不公开支持,属内部结构 -
spare4存的是带 salt 的双哈希(如S:8F2A1B3C/T:1A2B3C),不可逆,也无法直接爆破 - 12c+ 中部分配置下
spare4可能进一步被置空或截断
想确认密码状态,应该查 DBA_USERS.ACCOUNT_STATUS 和 DBA_PROFILES,而不是盯着 PASSWORD 列。
检查和清理必须分三步走,不能只改参数
发现普通用户能查 DBA_* 视图,别急着调 _O7_DICTIONARY_ACCESSIBILITY——它在运行时不可改,重启后也只影响极少数场景,对已授权用户完全无效。正确动作是:
- 查高危系统权限:
SELECT grantee, privilege FROM dba_sys_privs WHERE privilege = 'SELECT ANY DICTIONARY' - 查高危角色授权:
SELECT grantee, granted_role FROM dba_role_privs WHERE granted_role = 'SELECT_CATALOG_ROLE'(特别注意grantee = 'PUBLIC') - 查显式对象授权:
SELECT * FROM dba_tab_privs WHERE table_name LIKE 'DBA%' AND grantee = 'APP_USER'
真正容易被忽略的是:权限撤销后,用户会立刻失去访问能力,但已有连接的会话可能缓存了元数据;建议配合 ALTER SYSTEM KILL SESSION 清理活跃会话,避免误判“撤了没用”。











