唯一可靠方式是查询DBA_ROLE_PRIVS视图,需以SYS等高权限用户执行,核心语句为SELECT GRANTEE, ADMIN_OPTION, DEFAULT_ROLE FROM DBA_ROLE_PRIVS WHERE GRANTED_ROLE = 'DBA';同时须结合V$PWFILE_USERS、CDB_ROLE_PRIVS及sys.user$排查口令文件用户、CDB级授权和隐蔽账户。

查 DBA_ROLE_PRIVS 是唯一可靠方式
只看 DBA_ROLE_PRIVS,别用 USER_ROLE_PRIVS 或 ALL_ROLE_PRIVS ——它们只返回当前会话可见的角色,漏掉绝大多数 DBA 用户。必须以有权限的账号(如 SYS、SYSTEM 或已授 SELECT ANY DICTIONARY 的用户)执行。
核心语句就是:
SELECT GRANTEE, ADMIN_OPTION, DEFAULT_ROLE FROM DBA_ROLE_PRIVS WHERE GRANTED_ROLE = 'DBA';
-
GRANTED_ROLE必须写成'DBA'全大写,Oracle 内部统一存储为大写,小写或加引号的"dba"会匹配失败 -
GRANTEE可能是用户名,也可能是角色(比如APP_ADMIN),若只想看真实用户,得加过滤:AND GRANTEE IN (SELECT USERNAME FROM DBA_USERS) -
ADMIN_OPTION = 'YES'表示该用户能把 DBA 角色再授给别人,属于高危配置,需重点审计 -
DEFAULT_ROLE = 'YES'表示登录时自动激活 DBA 角色,无需手动SET ROLE
V$PWFILE_USERS 里的用户不等于 DBA,但更危险
一个用户可能没被授予 DBA 角色,却在 V$PWFILE_USERS 中 SYSDBA = 'TRUE' ——这意味着他能绕过所有密码验证和角色控制,直接以 SYS 身份登录并执行 ALTER SYSTEM 等操作。
查这个视图需要 SELECT ANY DICTIONARY 或 SELECT_CATALOG_ROLE 权限,普通 DBA 用户默认无权访问。
- 执行:
SELECT USERNAME, SYSDBA, SYSOPER FROM V$PWFILE_USERS; - 注意:该视图只反映口令文件中的条目,不包含通过 OS 认证(如
dba组成员直连)获得SYSDBA的情况 - 如果某用户同时出现在
DBA_ROLE_PRIVS和V$PWFILE_USERS中,说明存在双重高权限路径,风险叠加
多租户环境(CDB/PDB)下容易漏查
在 CDB 架构中,DBA_ROLE_PRIVS 默认只返回当前容器(PDB)内的授权记录。若未显式连接到根容器 CDB$ROOT,就会漏掉在 CDB 级授予 DBA 的用户。
- 确认当前容器:
SELECT SYS_CONTEXT('USERENV', 'CON_NAME') FROM DUAL; - 查 CDB 级 DBA 授权,必须在
CDB$ROOT中运行:SELECT GRANTEE FROM CDB_ROLE_PRIVS WHERE GRANTED_ROLE = 'DBA' AND CON_ID = 0; -
CON_ID = 0表示 CDB 级别,不是 PDB;漏掉这个条件,结果就不完整
别信 DBA_USERS,有些 DBA 用户根本不在里面
DBA_USERS 只列常规数据库用户,而 Oracle 底层 sys.user$ 表里还藏着类型为 type# = 1 的隐蔽账户 —— 它们可能被误删元数据、由 OS 组直连,或本身就是内部用户(如 XS$NULL)。
- 查这类用户:
SELECT name FROM sys.user$ WHERE type# = 1 AND name NOT IN (SELECT username FROM dba_users); - 返回的
name需人工核对:是否含空格或特殊字符?是否被过滤逻辑忽略? - 尤其要检查这些名字是否也在
V$PWFILE_USERS中 —— 若同时存在,就构成绕过常规用户视图的隐蔽管理通道
真正关键的不是“有没有 DBA 角色”,而是“能不能以最高权限执行命令”。角色只是其中一条路,口令文件、OS 认证、底层用户表,每一条都可能成为盲区。


















