Oracle对象权限级联授予无死锁,仅导致传播失控;需查DBA_TAB_PRIVS中GRANTABLE='YES'记录定位源头并手动逐层回收,不可用CASCADE(Oracle不支持),推荐以角色替代WITH GRANT OPTION切断传播链。
oracle里没有“权限环状授予导致死锁”这回事——对象权限的 with grant option 不会产生锁或死锁,它只造成权限传播失控。真正的问题是:你查不到谁授了权、撤不干净、审计过不去、离职员工留下的权限还在生效。
为什么查 DBA_SYS_PRIVS 找不到问题源头
系统权限(比如 CREATE TABLE)走 DBA_SYS_PRIVS,但对象权限(比如 SELECT ON HR.EMPLOYEES)的级联授予只存在 DBA_TAB_PRIVS 里,且关键字段是 GRANTABLE。如果漏查这个视图,就等于在权限地图上闭着眼走路。
-
GRANTABLE = 'YES'表示该记录对应的是“可再授权”的那一次授予,不是最终接收者 - 同一个表、同一个权限,可能有多个
GRANTABLE = 'YES'记录(比如 A→B、B→C、C→D 各一条) -
DBA_SYS_PRIVS里永远不会有GRANTABLE字段,查它对定位级联毫无帮助
怎么一次性列出所有可传播的授权链
直接执行这条语句,结果按 GRANTOR 排序后,就能看出谁是“授权出口”:
SELECT grantee, owner, table_name, privilege, grantable, grantor FROM DBA_TAB_PRIVS WHERE grantable = 'YES' ORDER BY grantor, grantee;
注意:grantee 是被授予权限的人,grantor 是授出者;链条从 grantor 指向 grantee,不是反过来。
- 如果发现
SCOTT出现在grantor列,且GRANTABLE = 'YES',说明他被赋予了转授权力——这通常不该出现在生产环境 - 若某用户同时出现在
grantor和grantee列(比如 A→B,B→C,C→A),这不是数据库“环状”,而是人工操作失误,Oracle 不阻止这种授予,但会留下审计隐患 - RAC 环境下必须用
DBA_TAB_PRIVS(不是ALL_TAB_PRIVS),否则跨实例授权可能查漏
回收时为什么 REVOKE ... CASCADE 报错
Oracle 不支持 CASCADE 关键字用于对象权限回收——那是 PostgreSQL 的语法。你在 Oracle 里敲 REVOKE SELECT ON HR.EMPLOYEES FROM B CASCADE,只会得到 ORA-00933: SQL command not properly ended。
-
REVOKE默认只断开直接关系:撤掉 B 的权限,C 和 D 的权限依然有效,且DBA_TAB_PRIVS中他们的记录照常存在 - 必须手动或脚本生成下游回收语句,例如先查:
SELECT 'REVOKE ' || privilege || ' ON ' || owner || '.' || table_name || ' FROM ' || grantee || ';' FROM DBA_TAB_PRIVS WHERE grantor = 'B'; - 生产环境别直接执行生成的
REVOKE语句,先导出、人工核对、加注释,再分批执行
用角色替代 WITH GRANT OPTION 的实际卡点
把散落的 WITH GRANT OPTION 收编进角色,能切断传播链,但落地时容易卡在三处:
- 角色不能继承对象权限的
WITH GRANT OPTION—— 即使你给角色授了SELECT ON HR.EMPLOYEES WITH GRANT OPTION,角色成员也无法再转授;这是设计使然,不是 bug - 已有用户可能同时拥有直接授予 + 角色授予,得先
REVOKE直接权限,再GRANT角色,否则权限叠加可能导致误操作 - 应用连接用的是密码登录而非角色激活(比如没设
DEFAULT ROLE),光授角色没用,还得确认SESSION_ROLES里真有它
最易被忽略的是:角色本身不解决“谁授的权”这个追溯问题,它只是让权限变得可批量管理;源头仍要靠 DBA_TAB_PRIVS 定期扫描 GRANTABLE = 'YES' 记录来堵漏。


















