必须优先撤销public对utl_file、utl_http、utl_tcp、dbms_random等高危包的execute权限,严禁直接撤销select any table,否则将导致standard包失效、大量对象invalid及ora-06553错误。
直接撤销 public 角色上的权限是可行的,但必须极度谨慎——oracle 中 public 是隐式授予所有用户的默认角色,对它的修改可能引发大量对象失效或应用报错(比如 ora-00942: table or view does not exist),尤其是撤销 execute 权限后,依赖 dbms_* 包的存储过程会立即失败。
查清到底授予了什么危险权限
别猜,先确认。PUBLIC 上常见的高危权限包括 EXECUTE on UTL_FILE、UTL_HTTP、DBMS_LOB、DBMS_RANDOM 等,以及 SELECT on ALL_* 或 DBA_* 视图。执行:
SELECT grantee, privilege, owner, table_name
FROM dba_tab_privs
WHERE grantee = 'PUBLIC'
AND privilege IN ('EXECUTE', 'SELECT')
AND (table_name IN ('UTL_FILE','UTL_HTTP','UTL_TCP','DBMS_LOB','DBMS_RANDOM','DBMS_SQL')
OR owner = 'SYS' AND table_name LIKE 'DBA_%');
注意:DBA_* 视图本身不被 PUBLIC 默认拥有权限,但有些 DBA 会手动授予,务必查实。
用 REVOKE 语句精准撤销,不能带 CASCADE
REVOKE 对 PUBLIC 不支持 CASCADE 选项,强行加会报 ORA-01957: illegal option for REVOKE。必须逐条撤销,且需以 SYS 或具有 GRANT ANY OBJECT PRIVILEGE 的用户执行:
REVOKE EXECUTE ON UTL_HTTP FROM PUBLIC;REVOKE EXECUTE ON UTL_TCP FROM PUBLIC;-
REVOKE SELECT ON DBA_USERS FROM PUBLIC;(如果真存在)
撤销后不会自动刷新已编译的 PL/SQL 对象,依赖这些包的函数/过程仍能运行,但下次重新编译时会报错 —— 所以要同步检查并修复相关代码。
撤销后必须验证依赖对象是否失效
撤销不是终点,而是风险暴露的开始。重点检查:
- 所有状态为
INVALID的PROCEDURE、FUNCTION、PACKAGE(查dba_objects where status = 'INVALID') - 应用日志中是否出现
PLS-00201: identifier must be declared或ORA-00904: invalid identifier - 是否有作业(
DBA_SCHEDULER_JOBS)因调用被撤权限的包而失败
常见坑:开发环境没跑全链路测试,上线后定时任务凌晨三点崩掉,没人值班。
别忘了清理 PUBLIC 上的同义词
有些 DBA 会为方便,在 PUBLIC 上创建指向危险包的同义词,比如:CREATE PUBLIC SYNONYM UTL_HTTP FOR SYS.UTL_HTTP;。仅撤销权限不够,还得删同义词:
DROP PUBLIC SYNONYM UTL_HTTP;
否则用户仍可通过同义词访问(只要权限没被 revoke),而且 DROP PUBLIC SYNONYM 不需要对象所有者权限,但需 DROP PUBLIC SYNONYM 系统权限。
真正麻烦的从来不是怎么 revoke,而是你不知道哪些应用悄悄依赖了 PUBLIC 的某条 EXECUTE 权限;生产库上动它之前,最好在归档日志可闪回的测试库里完整跑一遍业务链路。











