SELECT ANY TABLE无法访问SYS模式对象,因Oracle 9i起实施解析阶段拦截;须授SELECT ANY DICTIONARY或显式授权v_$session等视图,禁用O7_DICTIONARY_ACCESSIBILITY。

因为默认情况下,SELECT ANY TABLE 权限无法访问 SYS 模式下的基表和动态性能视图(如 v$session),这是 Oracle 9i 起的硬性安全限制,与权限本身是否授予无关。
ORA-00942 错误不是权限没给,而是对象不可见
你执行 GRANT SELECT ANY TABLE TO scott 后,scott 确实能查 HR.EMPLOYEES、SCOTT.DEPT,但执行 SELECT * FROM v$session 或 SELECT * FROM sys.obj$ 仍报 ORA-00942: table or view does not exist。这不是权限缺失,而是 Oracle 在解析阶段就拒绝识别这些对象——它根本“看不见”它们。
原因在于:v$session 是同义词,指向底层 v_$session;而 v_$session 是 SYS 模式下的视图,受数据字典访问控制机制拦截。
-
O7_DICTIONARY_ACCESSIBILITY参数默认为FALSE(Oracle 9i+) - 此时
SELECT ANY TABLE只覆盖普通用户 Schema 下的对象,不穿透到SYS的实体表或v_$*视图 - 即使你显式写
SELECT * FROM sys.v_$session,也会被拒绝,因为解析器在权限检查前就判定该对象“不存在”
想查 SYS 对象,必须用 SELECT ANY DICTIONARY 或调低兼容性
两种合法路径:
-
推荐:授
SELECT ANY DICTIONARY—— 这是 Oracle 9i 引入的专用系统权限,允许读取所有数据字典视图(包括dba_*、v$*、gv$*)和SYS下的实体视图(如sys.user$),且不依赖O7_DICTIONARY_ACCESSIBILITY - 不推荐:设
O7_DICTIONARY_ACCESSIBILITY = TRUE - 这会让
SELECT ANY TABLE“升级”为真正意义上的任意表(含SYS基表),但极大削弱安全边界,等同于开放数据库底层结构 - 该参数修改需重启实例,且影响全局,DBA 通常禁止启用
验证方式:SELECT * FROM session_privs WHERE privilege = 'SELECT ANY DICTIONARY';
别踩坑:直接 grant select on v$xxx 是无效的
很多人试过:GRANT SELECT ON v$session TO scott,结果报 ORA-02030: 只能从固定的表/视图查询。
-
v$session是同义词,不是真实对象,不能直接授权 - 正确做法是授
v_$session:GRANT SELECT ON v_$session TO scott - 但注意:
v_$session属于SYS,普通用户无权直接引用,除非已具备SELECT ANY DICTIONARY或SELECT_CATALOG_ROLE -
SELECT_CATALOG_ROLE可查部分dba_*视图,但不包含v_$*,也不含SYS实体表
真正需要的是最小权限,不是“ANY”
绝大多数场景根本不需要碰 SYS 表。比如监控会话,用 SELECT * FROM v$session 只是习惯;实际只需:
-
GRANT SELECT ON v_$session TO app_monitor+GRANT SELECT ON v_$process TO app_monitor - 或更安全地,建一个包装视图:
CREATE VIEW app_active_sessions AS SELECT sid, serial#, username, status FROM v_$session WHERE type = 'USER';,再授SELECT权限给该视图 - 避免把
SELECT ANY DICTIONARY给应用账号——它能读sys.user$密码哈希,风险极高
关键点在于:权限越具体,审计越清晰,回收越干净。一旦用了 ANY 类权限,你就失去了对“谁在查什么”的精确控制能力。











