不加 authid current_user 就没有真正权限控制:oracle 存储过程默认为定义者权限(authid definer),execute immediate 绕过调用者权限校验,所有 sql 以创建者身份执行;加 authid current_user 后才按调用者身份校验每条语句权限,并启用角色权限、解析当前 schema 对象。

不加 AUTHID CURRENT_USER 就没有真正权限控制
Oracle 存储过程默认是 AUTHID DEFINER(定义者权限),这意味着过程里所有 SQL——包括 EXECUTE IMMEDIATE——都以创建者身份运行。哪怕你只给调用者 EXECUTE 权限,只要创建者有删表权限,调用者就能删表。
常见错误现象:
- DBA 给用户授了
DBA角色,但过程编译失败,报ORA-01031: insufficient privileges - 用户能成功执行过程,却意外读到了本不该访问的
dba_objects或其他 schema 下的表 - 过程里建临时表失败,提示“表或视图不存在”,而该表明明在调用者 schema 下存在
根本原因:定义者权限下,角色权限(如 DBA)被禁用,且所有对象解析都按创建者 schema 进行,不看调用者当前 schema。
加了 AUTHID CURRENT_USER 后权限才按调用者校验
AUTHID CURRENT_USER 切换为调用者权限(Invoker’s Rights),过程内每条语句(含动态 SQL)都会检查调用者是否具备对应权限,且对象解析默认走调用者的 CURRENT_SCHEMA(可通过 ALTER SESSION SET CURRENT_SCHEMA 修改)。
关键影响点:
- 调用者必须显式拥有目标表的
SELECT/INSERT等权限,不能靠角色间接获得(除非启用 role) -
EXECUTE IMMEDIATE 'SELECT * FROM employees'会检查调用者是否有SELECT ON employees,不是创建者 - 如果调用者 schema 下没有
employees表,又没写 schema 前缀,就会报ORA-00942 - 角色权限在
AUTHID CURRENT_USER下默认可用(区别于 DEFINER)——这是它解决“DBA 角色不生效”问题的核心机制
示例:用户 scott 有 DBA 角色,过程里要建表:CREATE OR REPLACE PROCEDURE p_create_tmp AUTHID CURRENT_USER AS BEGIN EXECUTE IMMEDIATE 'CREATE TABLE tmp AS SELECT 1 a FROM DUAL'; END;
不加 AUTHID CURRENT_USER 会失败;加了就能过,因为此时 DBA 角色生效。
动态 SQL 拼接表名/列名会让 AUTHID CURRENT_USER 形同虚设
即使声明了 AUTHID CURRENT_USER,只要你在 EXECUTE IMMEDIATE 中拼接不可信输入,权限校验就彻底失效。数据库只校验最终语句语法与对象是否存在,不追溯来源。
危险写法:
-
v_table := user_input; EXECUTE IMMEDIATE 'SELECT * FROM ' || v_table;—— 输入'salaries' || ' WHERE 1=1 --'可绕过所有限制 -
EXECUTE IMMEDIATE 'UPDATE ' || v_table || ' SET ' || v_col || ' = :val' USING val;—— 列名、表名未白名单校验即注入
安全做法:
- 所有拼接的标识符(表名、列名)必须通过
DBMS_ASSERT.SQL_OBJECT_NAME或DBMS_ASSERT.SIMPLE_SQL_NAME校验 - 优先用静态 SQL;若必须动态,限定可选范围(如查配置表预定义表名列表)
- 避免把用户输入直接拼进 SQL 字符串,改用绑定变量处理值,而非结构
容易忽略的 schema 解析和权限继承细节
AUTHID CURRENT_USER 不改变过程本身的执行权限授予逻辑——GRANT EXECUTE ON proc TO user 仍是必需的。但它彻底改变了过程体内 SQL 的执行上下文,而这常被低估。
典型疏漏:
- 忘记调用者可能没有
SELECT_CATALOG_ROLE,导致查dba_*视图失败,应改用all_*或user_* - 过程里写
INSERT INTO orders ...,但调用者 schema 下无orders表,也未授权INSERT ON hr.orders,结果报ORA-00942而非权限不足 - 误以为加了
AUTHID CURRENT_USER就自动能跨 schema 操作——其实仍需显式GRANT,只是现在校验对象是调用者能访问的那些 - 在包(package)中使用时,必须对 package specification 和 body 都声明
AUTHID CURRENT_USER,否则无效
最麻烦的一点:权限错误往往不报 ORA-01031,而是报 ORA-00942 或 ORA-01747,让人误判为对象不存在或语法错,实际是权限上下文没对上。











