必须逐项确认、精准撤销、同步验证PUBLIC危险权限,严禁CASCADE;先查DBA_TAB_PRIVS定位高危EXECUTE/SELECT权限,再用REVOKE逐条撤销,补删PUBLIC同义词,并验证对象状态与作业失败情况。

不能直接“批量清理”PUBLIC,必须逐项确认、精准撤销、同步验证——否则立刻引发ORA-00942、PLS-00201或ORA-06553等连锁失效。
先查清PUBLIC到底被授了哪些危险权限
别凭记忆删,DBA_TAB_PRIVS才是唯一可信来源。重点盯EXECUTE on UTL_FILE、UTL_HTTP、UTL_TCP、DBMS_LOB、DBMS_RANDOM,以及SELECT on DBA_USERS、DBA_TAB_PRIVS等高危对象:
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')
OR (owner = 'SYS' AND table_name LIKE 'DBA_%')
);注意:DBA_*视图默认不授给PUBLIC,但DBA手动加的必须查实;ALL_*视图权限影响较小,可暂缓处理。
用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 DBMS_RANDOM FROM PUBLIC;-
REVOKE SELECT ON DBA_USERS FROM PUBLIC;(仅当上一步查到存在时)
撤销后权限立即生效,但已编译的PL/SQL对象(如PACKAGE BODY)不会自动失效——它们仍能运行,直到下次重新编译才暴雷。这点极易被忽略。
顺手干掉PUBLIC同义词,否则白撤
有些环境为图省事建了PUBLIC SYNONYM,比如:
CREATE PUBLIC SYNONYM UTL_HTTP FOR SYS.UTL_HTTP;
仅REVOKE EXECUTE没用,用户仍可通过同义词调用。必须补删:
DROP PUBLIC SYNONYM UTL_HTTP;DROP PUBLIC SYNONYM DBMS_LOB;
查同义词用:SELECT * FROM dba_synonyms WHERE owner = 'PUBLIC' AND synonym_name IN ('UTL_HTTP', 'DBMS_LOB');
撤销后必须立刻验证依赖对象状态
撤销不是终点,是问题暴露的起点。立刻检查:
SELECT object_name, object_type, status FROM dba_objects WHERE status = 'INVALID' AND owner NOT IN ('SYS','SYSTEM');- 应用日志里是否出现
PLS-00201: identifier must be declared(包不可见)或ORA-00904: invalid identifier(列/函数名错) -
SELECT job_name, state, failure_count FROM dba_scheduler_jobs WHERE state = 'FAILED';——定时任务常因调用UTL_*失败而静默挂起
最危险的是:开发环境没跑全链路,上线后凌晨三点某作业崩掉,没人值班。PUBLIC权限回收,本质是把隐性依赖显性化,再一个个修掉——这才是“彻底”的真实含义。


















