最直接的高危信号是用户被授予DBA角色,因其默认拥有ALTER SYSTEM、DROP ANY TABLE等数百项高危权限,且可绕过多数审计控制;需用SELECT grantee, admin_option, default_role FROM dba_role_privs WHERE granted_role = 'DBA' AND grantee NOT IN ('SYS','SYSTEM','SYSBACKUP','SYSDG','SYSKM')定位非运维账号,并重点核查admin_option='YES'及COMMON='YES'情形。

查谁有 DBA 角色——最直接的高危信号
DBA 角色是 Oracle 中权限最大的内置角色,几乎等价于 root。只要用户被授予 DBA,就默认拥有 ALTER SYSTEM、DROP ANY TABLE、CREATE ANY PROCEDURE 等数百项系统权限,且能绕过大部分审计和 Vault 控制。
执行以下语句定位所有拥有该角色的用户(需 SYS 或具备 SELECT_CATALOG_ROLE 的账号):
SELECT grantee, admin_option, default_role
FROM dba_role_privs
WHERE granted_role = 'DBA'
AND grantee NOT IN ('SYS', 'SYSTEM', 'SYSBACKUP', 'SYSDG', 'SYSKM');注意:admin_option = 'YES' 表示该用户还能把 DBA 再授给他人,风险指数翻倍;default_role = 'NO' 不代表安全——只要执行 SET ROLE DBA 就立刻激活。
- 生产环境里,除运维 DBA 账号外,应用账号、ETL 账号、报表账号绝不应出现在结果中
- 若看到
APP_USER或ETL_JOB在列,优先回收,不要等出事再补救 -
COMMON = 'YES'出现在多租户(CDB)中,表示该授权跨 PDB 生效,影响面更大
识别隐式继承的高危权限链——光看 DBA 还不够
很多用户没直接被授 DBA,但通过角色嵌套(比如 RESOURCE → SELECT_CATALOG_ROLE → EXECUTE_CATALOG_ROLE)间接拿到 SELECT ANY DICTIONARY 或 EXECUTE ANY PROCEDURE,一样能读取敏感数据、执行任意 PL/SQL 包。
要挖出这类“影子高权限”,必须递归查角色链。例如查 SCOTT 的完整系统权限集合:
WITH role_path (grantee, role, level#) AS (
SELECT grantee, granted_role, 1
FROM dba_role_privs
WHERE grantee = 'SCOTT'
UNION ALL
SELECT r.grantee, p.granted_role, rp.level# + 1
FROM dba_role_privs p
JOIN role_path r ON p.grantee = r.role
WHERE rp.level# < 4
)
SELECT DISTINCT s.privilege
FROM role_path r
JOIN role_sys_privs s ON r.role = s.role
WHERE s.privilege IN ('SELECT ANY DICTIONARY', 'EXECUTE ANY PROCEDURE', 'DROP ANY TABLE', 'ALTER DATABASE');这个查询只展开 4 层(避免无限递归),已覆盖绝大多数生产环境的角色嵌套深度。
-
SELECT ANY DICTIONARY是最大隐患之一:它允许读取DBA_USERS、DBA_TAB_PRIVS等元数据,等于掌握全库权限地图 -
EXECUTE ANY PROCEDURE可调用UTL_HTTP、UTL_FILE等危险包,常被用于提权或外连 - 别忽略
GRANT ANY PRIVILEGE和GRANT ANY ROLE——它们让普通用户变成权限分发者
验证当前会话是否真能行使这些权限——别信视图快照
DBA_SYS_PRIVS 和角色链查询反映的是“授权状态”,不是“生效能力”。用户可能被授了 DBA,但没执行 SET ROLE DBA,或者其 profile 限制了角色激活(如 SEC_MAX_FAILED_LOGIN_ATTEMPTS 触发后角色自动失效)。
唯一可信的判断依据是 SESSION_PRIVS:
CONNECT scott/tiger; SELECT * FROM session_privs;
如果返回空,说明当前会话没激活任何高危权限,哪怕 DBA_SYS_PRIVS 显示他有 ALTER SYSTEM,此刻也用不了。
- 执行
SET ROLE ALL后立刻重查SESSION_PRIVS,观察权限是否补全 - 若仍为空,检查
dba_users.account_status是否为OPEN,以及profile中ROLE_LIMIT是否设为UNLIMITED - 在 Database Vault 启用环境下,
SESSION_PRIVS可能被进一步过滤——Vault 规则优先于角色授权
回收与加固——最小权限落地的关键动作
发现高危用户后,不能只删角色,还要确认替代方案是否就位,否则业务会中断。回收顺序建议从宽到严:
- 先回收
WITH ADMIN OPTION:对已有DBA用户执行REVOKE ADMIN OPTION FOR DBA FROM username,阻断权限扩散链 - 再替换角色:用自定义角色替代
DBA,例如只授CREATE SESSION、SELECT ANY TABLE(加白名单表)、INSERT ON app_log,其余全砍 - 禁用危险权限:对必须保留的账号,显式回收高危项:
REVOKE SELECT ANY DICTIONARY FROM username - 锁定 profile:修改其 profile,设置
FAILED_LOGIN_ATTEMPTS = 3、PASSWORD_LOCK_TIME = 1、PASSWORD_REUSE_MAX = 5
真正难的不是查和收,而是搞清“这个用户到底需要哪些权限才能跑通业务”。一次粗暴回收可能让 ETL 脚本静默失败,日志里只报 ORA-01031,不告诉你缺哪条权限。所以修复前务必做权限最小化测试——用 SQL_TRACE 或 DBMS_MONITOR 捕获真实操作流,再反向精简授权。


















