一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

怎样在Oracle中为开发者创建只能查看执行计划的用户

时间:2026-07-02 11:15:51 编辑:袖梨 来源:一聚教程网

不能直接授SELECT_CATALOG_ROLE,因其包含DBA_*等高危视图权限,会泄露密码哈希、用户信息等敏感数据;应仅授予V$SQL、V$SQL_PLAN、V$SQL_PLAN_STATISTICS_ALL三个最小必要视图权限,并禁用CREATE PROCEDURE和CREATE SYNONYM权限以防绕过。

直接给用户 select any dictionaryselect_catalog_role 是最常见也最危险的做法——它会让开发者顺手查到 dba_usersdba_tab_privs 甚至加密密码哈希,远超“看执行计划”所需。

为什么不能直接授 SELECT_CATALOG_ROLE?

这个角色包含对 V$SQL_PLANV$SQL_PLAN_STATISTICS_ALL 等视图的 SELECT 权限,但同时也开了 DBA_*ALL_* 大量高危视图的门。更关键的是:它不区分“谁的 SQL”,用户能查到所有会话(包括生产应用)的执行计划,可能暴露敏感 SQL 逻辑或绑定变量值。

常见错误现象:
– 用户执行 SELECT * FROM V$SQL_PLAN WHERE SQL_ID = 'xxx' 成功,但紧接着 SELECT PASSWORD FROM DBA_USERS 也成功
– 开发者用 PL/SQL Developer 连接后,在“对象浏览器”里展开 DBA 节点,看到全部用户、表空间、审计策略

只开 V$ 视图的最小权限组合

Oracle 的 V$ 视图是基于底层 X$ 内存结构的封装,权限控制粒度很粗,但可精确限定到具体视图。真正需要的只有三个:

  • V$SQL_PLAN:核心,查任意 SQL 的执行计划(需配合 SQL_ID
  • V$SQL_PLAN_STATISTICS_ALL:带实际运行统计(如 buffer gets、rows processed),调试性能必须
  • V$SQL:用于根据 SQL 文本反查 SQL_ID,否则开发者连目标 SQL 都找不到

授权语句必须逐个执行(不能用通配符):

GRANT SELECT ON SYS.V$SQL TO dev_plan_user;<br>GRANT SELECT ON SYS.V$SQL_PLAN TO dev_plan_user;<br>GRANT SELECT ON SYS.V$SQL_PLAN_STATISTICS_ALL TO dev_plan_user;

注意:
– 所有视图都属于 SYS Schema,必须写全 SYS.V$XXX
– 授权时不能省略 SYS. 前缀,否则报错 ORA-00942
– 不要授予 V$SESSIONV$PROCESS,否则能关联出谁在跑什么 SQL

如何防止用户绕过限制查其他东西?

即使只授了这三个视图,用户仍可能通过以下方式越权:

  • EXECUTE IMMEDIATE 动态拼接查询其他 V$ 视图(如 V$DATABASE)——必须禁用该用户的 CREATE PROCEDURE 权限
  • 利用同义词指向敏感视图——禁止其创建同义词:REVOKE CREATE SYNONYM FROM dev_plan_user
  • 通过 DBMS_XPLAN.DISPLAY_CURSOR 查计划但不依赖视图——这个包本身需要 SELECT_CATALOG_ROLE 或显式授权,只要没授就不可用

验证是否干净:

SELECT * FROM SESSION_PRIVS;<br>-- 输出应仅含 CONNECT、SELECT ANY DICTIONARY(若你误授)、以及上面三个 SELECT ON SYS.V$* 权限<br>-- 不应出现 CREATE PROCEDURE、CREATE SYNONYM、UNLIMITED TABLESPACE 等

开发者实际怎么用?给一个安全的查询模板

用户登录后,典型操作是查某条慢 SQL 的计划。正确流程是:

  1. 先从 V$SQLSQL_ID(过滤条件必须加,避免扫全表):
    SELECT SQL_ID, SQL_TEXT FROM V$SQL WHERE SQL_TEXT LIKE '%WHERE order_id = %' AND ROWNUM <= 5;
  2. 再用 SQL_ID 查计划:
    SELECT * FROM V$SQL_PLAN WHERE SQL_ID = 'abc123...' ORDER BY ID;
  3. 如需真实执行统计:
    SELECT * FROM V$SQL_PLAN_STATISTICS_ALL WHERE SQL_ID = 'abc123...' AND LAST_ACTIVE_TIME > SYSDATE - 1/24;

关键细节:
– 所有查询必须显式指定 WHERE 条件,尤其 V$SQL 行数巨大,不加限制会卡死会话
V$SQL_PLAN_STATISTICS_ALL 默认只保留最近缓存的计划,旧 SQL 可能查不到,这不是权限问题,是 Oracle 内存管理机制

真正容易被忽略的点:V$ 视图返回的是当前实例内存中的快照,不是归档历史;如果 SQL 已被老化出共享池,就查不到任何记录——这和权限无关,但常被误判为“权限没生效”。

热门栏目