This example assumes the following
- 数据库有两个用户 TOM 和 NATASHA
- TOM 用户下有张表 TOM_DATE
- TOM 用户下有个存储过程 TOM_PRO_INSERT(过程中用到表 TOM_DATE)
- TOM 用户把存储过程的 EXECUTE 权限授权给 NATASHA
实验脚本如下
# 创建 TOM 用户
[oracle@henry ~]$ sqlplus sys/oracle@pdb1 as sysdba
SQL*Plus: Release 12.2.0.1.0 Production on Wed Mar 18 18:08:18 2020
Copyright (c) 1982, 2016, Oracle. All rights reserved.
Connected to:
Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
SQL> create user tom identified by tom;
User created.
SQL> grant dba to tom;
Grant succeeded.
# 创建 NATASHA 用户
SQL> create user natasha identified by natasha;
User created.
SQL> grant connect,resource to natasha;
Grant succeeded.
# TOM 下创建表 TOM_DATE
SQL> conn tom/tom@pdb1;
Connected.
SQL> create table tom_date(rq date default sysdate);
Table created.
# TOM 下创建存储过程 TOM_PRO_INSERT
SQL> create or replace procedure tom_pro_insert
2 as
3 begin
4 insert into tom_date values(default);
5 end;
6 /
Procedure created.
# TOM 对 NATASHA 进行存储过程执行授权
SQL> grant execute on tom_pro_insert to natasha;
Grant succeeded.
There Is A Problem
这里你回顾下权限知识点(系统权限、对象权限、角色权限),TOM 用户创建的存储过程,TOM 当然可以执行。执行存储过程查看结果:
SQL> show user;
USER is "TOM"
SQL> exec tom_pro_insert;
PL/SQL procedure successfully completed.
SQL> select * from tom_date;
RQ
-------------------
2020-03-18 18:20:38
因为 TOM 把该存储过程的执行权限给了 NATASHA,所以 NATASHA 也当然可以执行啦。切换 NATASHA 执行存储过程:
SQL> conn natasha/natasha@pdb1;
Connected.
SQL> show user
USER is "NATASHA"
SQL> exec tom.tom_pro_insert;
PL/SQL procedure successfully completed.
SQL> commit;
Commit complete.
存储过程执行成功,但里面有个小细节。TOM 用户授权的是存储过程给 NATASHA,而存储过程里面涉及到表 TOM_DATE 对 NATASHA 是没有任何权限的。但是 NATASHA 依然可以通过该存储过程对表进行插入操作。那请问?用户 NATASHA 成功执行存储过程后,她可以直接查询 TOM 用户下的 TOM_DATE 表吗?
SQL> show user
USER is "NATASHA"
SQL> select * from tom.tom_date;
select * from tom.tom_date
*
ERROR at line 1:
ORA-00942: table or view does not exist
显然不阔以!但执行存储过程后,数据确实被插入了,切换 TOM 查看数据。
SQL> conn tom/tom@pdb1
Connected.
SQL> show user
USER is "TOM"
SQL> select * from tom_date;
RQ
-------------------
2020-03-18 18:20:38
2020-03-18 18:23:23
这个问题你看清楚了吗?所以接下来引入 Definer's Rights (定义者权限)和 Invoker's Rights (调用者权限)
What Are Invoker's Rights and Definer's Rights
- Definer's Rights
如果你在创建存储过程或者函数的时候,是这样定义的:
CREATE OR REPLACE PROCEDURE askscuti
AS ...
# 或者带了授权标识
CREATE OR REPLACE PROCEDURE askscuti AUTHID DEFINER
AS ...
上面两句命令是一样的,就是用定义者的权限定义的存储过程,第一句默认缺省的授权标识就是 DEFINER ,如果该存储过程的执行权限授权给了其他用户,那么其他用户可以执行该存储过程(即使存储过程里面涉及到的对象对于被授权用户没有任何权限)。文章开头做的那个实验,指的就是这种情况。
- Invoker's Rights
如果你在创建存储过程或者函数的时候,是这样定义的:
CREATE OR REPLACE PROCEDURE askscuti AUTHID CURRENT_USER
AS ...
授权标识定义成了 CURRENT_USER,就是用调用者的权限定义的存储过程,如果该存储过程的执行权限授权给了其他用户,但是被授权的这个用户对存储过程里面的对象没有权限的话,存储过程是无法执行成功的。通过下面这个实验看下。
通过实验理解 Invoker's Rights
# TOM 下创建表 TOM_DATE_T
SQL> conn tom/tom@pdb1;
Connected.
SQL> create table tom_date_t(rq date default sysdate);
Table created.
# TOM 下创建存储过程 TOM_PRO_INSERT_INVOKER
SQL> create or replace procedure tom_pro_insert_invoker AUTHID CURRENT_USER
2 as
3 begin
4 insert into tom_date_t values(default);
5 end;
6 /
Procedure created.
# TOM 对 NATASHA 进行存储过程执行授权
SQL> grant execute on tom_pro_insert_invoker to natasha;
Grant succeeded.
TOM 执行该存储过程并查询表
SQL> show user
USER is "TOM"
SQL> exec tom_pro_insert_invoker;
PL/SQL procedure successfully completed.
SQL> select * from tom_date_t;
RQ
-------------------
2020-03-18 19:00:48
现在你觉得 NATASHA 用户可以执行这个存储过程吗?
SQL> conn natasha/natasha@pdb1;
Connected.
SQL> show user
USER is "NATASHA"
SQL> exec tom.tom_pro_insert_invoker;
BEGIN tom.tom_pro_insert_invoker; END;
*
ERROR at line 1:
ORA-00942: table or view does not exist
ORA-06512: at "TOM.TOM_PRO_INSERT_INVOKER", line 4
ORA-06512: at line 1
这里你对比下和第一次实验的区别。因为第二次创建的存储过程使用的授权标识为 Invoker's Rights 调用者权限。因此即使授权了存储过程的执行权限,因着 NATASHA 没有存储过程中所涉及到的对象权限(表 tom_date_t),所以执行失败。
最后来道题目瞅瞅
In your multitenant container database (CDB) containing pluggable database (PDBs), the
HR user executes the following commands to create and grant privileges on a procedure:
CREATE OR REPLACE PROCEDURE create_test_v (
v_emp_id NUMBER,
v_ename VARCHAR2,
v_SALARY NUMBER,
v_dept_id NUMBER)
BEGIN
INSERT INTO hr.test VALUES (V_emp_id, V_ename, V_salary, V_dept_id);
END;
/
GRANT EXECUTE ON CREATE_TEST_V TO john, jim, smith, king;
How can you prevent users having the EXECUTE privilege on the CREATE_TEST_V procedure from inserting values into tables on which they do not have any privileges?
A. Create the CREATE_TEST_V procedure with definer's rights.
B. Grant the EXECUTE privilege to users with GRANT OPTION on the CREATE_TEST_V procedure.
C. Create the CREATE_TEST_V procedure with invoker's rights.
D. Create the CREATE_TEST_V procedure as part of a package and grant users the EXECUTE privilege the package.
你觉得答案是哪个?Answer: 我是白色的 -> C