PUBLIC角色被授予的对象权限需查DBA_TAB_PRIVS(GRANTEE='PUBLIC'),系统权限需查DBA_SYS_PRIVS;二者缺一不可,且须注意大小写、间接授权及撤销风险。
查 PUBLIC 角色被授予了哪些对象权限
直接查 dba_tab_privs 是最有效的方式,因为所有显式授予 public 的表、视图、序列等对象权限都落在此视图中。注意 grantee = 'public' 必须全大写,oracle 系统视图里值是大写的。
常见错误是漏掉条件或拼错 'PUBLIC'(比如写成 'public' 或 'Public'),结果返回空——不是没授,是条件没匹配上。
执行这条语句就能看到全部:
SELECT GRANTOR, OWNER, TABLE_NAME, PRIVILEGE, GRANTABLE FROM DBA_TAB_PRIVS WHERE GRANTEE = 'PUBLIC' ORDER BY OWNER, TABLE_NAME, PRIVILEGE;
特别关注以下高危组合:
-
PRIVILEGE = 'EXECUTE'且TABLE_NAME是UTL_FILE、UTL_HTTP、DBMS_LOB等内置包 -
PRIVILEGE = 'SELECT'或'UPDATE'等对业务敏感表(如TT_03_24577_L)的授权 -
GRANTABLE = 'YES'—— 表示该权限还能被 PUBLIC 成员再转授,风险倍增
查 PUBLIC 角色被授予了哪些系统权限
DBA_SYS_PRIVS 存的是系统级权限(如 CREATE SESSION、SELECT ANY TABLE),而 PUBLIC 作为特殊接收者,也能被直接授予这些权限——虽然少见,但一旦存在,影响范围是全局的。
执行:
SELECT GRANTEE, PRIVILEGE, ADMIN_OPTION FROM DBA_SYS_PRIVS WHERE GRANTEE = 'PUBLIC';
如果返回结果,必须立刻评估:这些权限是否真有必要开放给“所有用户”?例如 SELECT ANY DICTIONARY 或 UNLIMITED TABLESPACE 几乎从不合规。
注意:ADMIN_OPTION = 'YES' 意味着任意用户都能用这个权限去再授权,这是等保2.0明确禁止的行为。
为什么不能只靠 DBA_TAB_PRIVS 就认为 PUBLIC 没权限
有人查完 DBA_TAB_PRIVS WHERE GRANTEE = 'PUBLIC' 没结果,就以为“PUBLIC 没被授权”,这很危险。原因有二:
- 某些对象权限可能通过角色间接授予 PUBLIC,比如先
GRANT SELECT ON emp TO hr_role,再GRANT hr_role TO PUBLIC—— 这种链式授权不会出现在DBA_TAB_PRIVS中,因为GRANTEE字段存的是角色名,不是PUBLIC -
PUBLIC不是角色,也不是用户,它无法被查到在DBA_ROLE_PRIVS或DBA_USERS里;但它能出现在任何GRANTEE字段中,且仅在此处“可见”
所以合规检查时,必须把 DBA_TAB_PRIVS 和 DBA_SYS_PRIVS 两张表都扫一遍,缺一不可。
撤销 PUBLIC 权限时的关键约束
撤销操作本身很简单,比如 REVOKE SELECT ON TT_03_24577_L FROM PUBLIC;,但真正难的是判断“能不能撤”。很多 Oracle 应用(尤其是 TimeTen 缓存层)默认依赖 PUBLIC 权限启动或运行,贸然回收会导致服务中断。
实操前务必确认:
- 该权限是否被某个应用账号(如
TT用户)显式依赖?查它的连接会话和常用 SQL 是否含该对象 - 是否有其他角色或用户通过
GRANT ... WITH GRANT OPTION从 PUBLIC 继承了该权限?撤销后他们的权限也会消失 - 是否已在测试库完整回归验证?生产环境严禁跳过这步
最容易被忽略的一点:撤销后,要立刻重新查一遍 DBA_TAB_PRIVS,确认对应行已消失——因为 Oracle 有时缓存权限元数据,需等待几分钟或执行 ALTER SYSTEM FLUSH SHARED_POOL; 才能实时反映。











