查dba_tab_privs必须指定owner,否则90%权限判断错误;需组合owner、table_name精确查询,区分系统权限与对象权限,关注public和grantable=’yes’高危信号。
直接查 dba_tab_privs 不加 owner 条件,90% 的“权限过大”判断都是错的
查谁对哪张表有啥权限,必须指定 OWNER
常见错误现象:执行 select * from dba_tab_privs where table_name = 'EMP',结果返回几十行——scott.emp、hr.emp、test.emp 全混在一起。你以为 scott 用户被滥授了权限,其实只是你没限定 schema。
-
OWNER是 schema 名,不是用户名(虽然多数一致,但 proxy 用户或重命名后可能分离) - 建表时没加双引号,表名和 owner 默认大写,查询也得用大写:
OWNER = 'SCOTT' AND TABLE_NAME = 'EMP' - 真正要定位“谁对 SCOTT.EMP 授了什么权”,必须组合条件:
OWNER = 'SCOTT' AND TABLE_NAME = 'EMP' - 如果目标是“查某用户被授予了哪些对象权限”,用
GRANTEE = 'APP_USER'比反向扫表更准、更快
系统权限和对象权限必须分开查,漏一张就等于漏一半风险
有人想“一次性看清用户所有权限”,只跑 DBA_SYS_PRIVS 或只跑 DBA_TAB_PRIVS,结果高危权限完全没看到。
-
DBA_SYS_PRIVS存系统级权限(如DROP ANY TABLE、ALTER SYSTEM),不涉及具体表 -
DBA_TAB_PRIVS存对象级权限(如对HR.EMPLOYEES的SELECT),不包含角色继承来的系统权限 - 若用户被授予了
DBA角色,它的所有系统权限都藏在DBA_ROLE_PRIVS+DBA_SYS_PRIVS的递归链里,不会出现在DBA_TAB_PRIVS中 - 查完整权限:先查
DBA_SYS_PRIVS where GRANTEE = 'USER',再查DBA_ROLE_PRIVS找出其角色,再查DBA_SYS_PRIVS where GRANTEE in (role_list)
PUBLIC 授权和 GRANTABLE = 'YES' 是真·高危信号
这两类授权不会在常规权限清单里显眼标红,但实际危害最大——前者全库可见,后者允许二次转授,极易失控。
-
select * from dba_tab_privs where GRANTEE = 'PUBLIC'—— 查所有对 PUBLIC 开放的对象权限,重点看INSERT、UPDATE、EXECUTE -
select * from dba_tab_privs where GRANTABLE = 'YES'—— 查谁有转授权能力,尤其警惕普通用户拥有此标记 -
ALL_TAB_PRIVS和USER_TAB_PRIVS不会返回PUBLIC授权记录,必须用DBA_TAB_PRIVS - 修复时别只 revoke 用户权限,要确认是否从角色继承而来——查
DBA_ROLE_PRIVS,再查角色本身权限
没 SELECT ANY DICTIONARY 权限时,DBA_* 视图根本不可见
执行 select * from dba_tab_privs 报 ORA-00942,不是视图不存在,而是你没权限读它。
- 降级用
ALL_TAB_PRIVS:只返回当前用户有 SELECT 权限的对象上的授权记录,PUBLIC授权和跨 schema 权限基本看不到 -
USER_TAB_PRIVS更窄:仅当前用户自己拥有的对象权限,对风险评估几乎无用 - 真正做权限审计,必须由有
SELECT ANY DICTIONARY的账号(如SYS)执行,否则“查不到”不等于“不存在” - 临时补救:让 DBA 运行
grant select any dictionary to your_user,但需严格控制时效和范围
权限收敛最难的不是 SQL 写不对,而是分不清“谁授的”“通过谁授的”“能不能转授”。GRANTEE 是用户还是角色、GRANTABLE 是否为 YES、OWNER 是否精确匹配——这三个字段不一起看,查出来的结果就是废数据。











