应查SELECT grantee FROM dba_role_privs WHERE granted_role = 'DBA' AND grantee IN (SELECT username FROM dba_users),因DBA角色权限最高,需精准定位显式授予该角色的真实用户。
查哪些用户有 DBA 角色
dba 角色是 oracle 中权限最高的预定义角色,拥有近乎完全的数据库控制权。它不是“能查所有表”那么简单,而是可以直接执行 create user、drop tablespace、alter system 等高危操作。
真正需要盯住的是被显式授予了 DBA 角色的用户,而不是靠猜测或看用户名判断:
-
SELECT grantee FROM dba_role_privs WHERE granted_role = 'DBA'—— 这是最直接、最可靠的查询方式 - 注意
grantee字段可能包含用户名,也可能包含其他角色(比如自定义角色嵌套),需进一步过滤非角色对象:AND grantee IN (SELECT username FROM dba_users) - 如果数据库启用了细粒度访问控制(FGAC)或统一审计,
DBA角色本身不会自动触发审计日志;必须单独配置审计策略才能捕获其行为
识别 SELECT ANY DICTIONARY 授权者
这个系统权限比 DBA 更隐蔽也更危险:它不赋予对象创建/删除能力,却能让用户绕过所有数据字典视图的访问限制,直接执行 SELECT * FROM dba_audit_trail、SELECT * FROM dba_encryption_keys 等敏感查询。
关键点在于它常被误当作“只读监控权限”而随意授予:
- 查谁有该权限:
SELECT grantee FROM dba_sys_privs WHERE privilege = 'SELECT ANY DICTIONARY' - 该权限由
GRANT ANY PRIVILEGE持有者或 DBA 授予,但授予者本身未必在结果中出现——要查授权链得结合dba_tab_privs和dba_role_privs回溯 - 即使用户账户已锁定(
ACCOUNT_STATUS = 'LOCKED')或过期,该权限依然有效;只要登录成功(比如通过 proxy 用户或密码重置),就能立即使用
用 session_privs 快速确认当前会话真实权限
很多权限问题出在“以为自己有,其实没有”或者“以为没生效,其实已激活”。session_privs 是唯一反映当前连接实际可用权限的视图,不依赖角色是否默认启用、也不受 SET ROLE 临时切换影响。
典型误判场景:
- 用户被授予了
SELECT_CATALOG_ROLE,但该角色未设为默认角色 →session_privs里看不到SELECT ANY DICTIONARY - DBA 角色被授予,但用户登录时指定了
SET ROLE NONE→session_privs不含ALTER DATABASE等系统权限 - 执行
SELECT * FROM session_privs前,确保连接用户不是SYS或SYSTEM(它们的权限列表极长,且部分权限在普通会话下不可见)
审计高权限操作必须覆盖的字典视图
仅靠查“谁有权限”不够,还得知道他们能查什么。Oracle 数据字典视图按前缀分三级,每级暴露的信息敏感度差异极大:
-
USER_*视图(如user_tables)只返回当前用户拥有的对象,基本无风险,一般无需审计 -
ALL_*视图(如all_tab_privs)返回当前用户“有权访问”的对象,可能泄露跨 schema 权限设计,建议对 DBA 和运维账号开启访问审计 -
DBA_*视图(如dba_users、dba_audit_trail、dba_encryption_keys)是真正的红线区域,任何对它们的查询都应记录到统一审计策略中;尤其注意dba_hist_*类历史视图,容易被用于绕过实时审计
最容易被忽略的是:SELECT ANY DICTIONARY 权限持有者可以直连 sys 模式下的底层基表(如 obj$、user$),这些表不在标准数据字典视图列表里,但审计策略若只配了 DBA_* 视图,就完全漏掉了。











