在Oracle中,系统权限、对象权限以及他们的集合角色权限,是一个相对复杂的安全体系。在前一篇《使用Role权限体系》()中,已经进行初步介绍。存储过程作为Schema对象下的程序单元,在进行Role处理时有一些特殊之处。今天我们继续介绍存储过程的权限体系:和。
在存储过程中,我们常常面对这样一个场景:用户A下有一个存储过程(或者函数体、包体)P,中间引用了对象X。在编译存储过程时,是要求用户A有对象X的权限的,如果没有,则系统报编译错误。当成功进行编译之后,用户A将执行execute存储过程P的权限赋给了用户B。但是用户B这时候不一定拥有X的使用权限,此时B能够成功执行存储过程P呢?我们通过一个简单,来证实一下。
实验环境准备
先准备用户test,除了具备基本的connect和resource角色权限之外,处于实验目的,赋给select any dictionary的系统权限给test。
SQL> conn sys/sys@otstest as sysdba;Connected to Oracle Database 10g EnterpriseEdition Release10.2.0.1.0Connected as SYSSQL>SQL> create user test 2 identified by test;User createdSQL> grant resource to test;Grant succeeded SQL> grant connect to test;Grant succeededSQL> grant select any dictionary to test;Grant succeeded
Select any dictionary的系统权限意味着用户可以访问数据字典视图层面的视图对象数据,而且不会因为存储过程对角色权限的剥离效应而受到影响。
SQL> conn test/test @otstest;Connected to Oracle Database10gEnterpriseEdition Release10.2.0.1.0Connected as testSQL> select count(*) fromdba_objects; COUNT(*)-------------- 53305SQL> create or replace procedure p_test_nc 2 is 3 i number; 4 begin 5 select count(*) 6 into i 7 from dba_objects; 8 9 dbms_output.put_line(to_char(i)); 10 end; 11 /Procedure createdSQL> set serveroutput on size 1000;SQL> exec p_test_nc;53306PL/SQL procedure successfully completed
可见,授予select any dictionary的用户test可以对dba_objects视图进行访问操作。同时,存储过程p_test_nc也可以顺利的编译执行。
实验一 —— 所有者权限
准备好的实验环境,我们准备进行第一个项目实验。建立一个新用户ts,只有执行test用户下p_test_nc存储过程权限,但是没有访问dba_objects视图权限,看实际效果。
SQL> conn sys/sys@otstest as sysdba;Connected to Oracle Database10gEnterpriseEdition Release10.2.0.1.0Connected as SYSSQL> create user ts 2 identified by ts;User createdSQL> grant resource to ts;Grant succeededSQL> grant connect to ts;Grant succeeded//用户ts只具有基本的连接和创建对象权限。SQL> conn test/test@otstest;Connected to Oracle Database10gEnterpriseEdition Release10.2.0.1.0Connected as test//将p_test_nc执行权限授权给tsSQL> grant execute on p_test_nc to ts;Grant succeeded
之后,我们检查ts用户下,p_test_nc的执行情况。
SQL> conn ts/ts@otstest;Connected to Oracle Database10gEnterpriseEdition Release10.2.0.1.0Connected as ts SQL> select count(*) from dba_objects; select count(*) from dba_objects//ts用户没有dba_objects权限,显示访问必然没有结果;ORA-00942:表或视图不存在SQL> set serveroutput on size 1000;SQL> exec test.p_test_nc;53306PL/SQL procedure successfully completed
结果显而易见,ts虽然没有访问dba_objects权限,但是因为拥有执行p_test_nc的权限,在执行p_test_nc的时候,也是可以在方法中访问到dba_objects。显然,此时ts在p_test_nc上借用了test用户对于dba_objects用户的权限,也就是对象所有者权限。
进一步证明我们的实验,可以进行些变化。
--当所有者权限失去时,即使调用者拥有权限也是无用的。
SQL> conn sys/sys@otstest as sysdba;Connected to Oracle Database10gEnterpriseEdition Release10.2.0.1.0Connected as SYS//回收了test用户上的select any dictionary权限,此时test对dba_objects对象权限消失;SQL> revoke select any dictionary from test;Revoke succeeded//赋予ts用户select any dictionary权限,这样ts就能访问dba_objects了;SQL> grant select any dictionary to ts;Grant succeededSQL> conn ts/ts@otstest;Connected to Oracle Database10gEnterpriseEdition Release10.2.0.1.0Connected as tsSQL> set serveroutput on size 1000;SQL> select count(*) from dba_objects;//可以访问对象 COUNT(*)---------- 53306SQL> exec test.p_test_nc;begin test.p_test_nc; end;ORA-06550:第1行,第12列:PLS-00905:对象TEST.P_TEST_NC无效ORA-06550:第1行,第7列:PL/SQL: Statement ignored
我们看到了一些“诡异现象”,ts用户拥有dba_objects对象访问权限,同时也有执行p_test_nc的权限,但是执行的时候却报错,认为对象无效。
唯一的原因就是因为test用户失去了dba_objects对象的权限。而ts在调用p_test_nc时使用的是dba_objects的权限。
上面,我们就介绍了Oracle在存储过程中使用的权限配置“所有者权限”。简单的说,当执行一个程序体(存储过程、函数和包等)的时候,方法体内部使用的权限体系为当前该程序体所有者的权限体系,而与调用方法的用户无关。存储过程p_test_nc此时,无论是谁在执行,权限体系都是该存储过程的所有者test的权限。
所有者权限是Oracle使用的默认权限选择方式,在使用的时候很方便。使用者只要拥有简单的对象执行权限就可以了,无需顾及自己是否有权限访问方法中使用的对象。
有了前面对的介绍,的含义就相对容易理解了。调用者权限体系就是执行方法体的时候,使用的权限按照调用者权限体系来判断。一个方法的执行,调用者除了要拥有方法的执行权限,还要拥有方法中使用对象的权限才可以。
二——调用者权限
我们继续实验一的环境。注意,此时test用户没有select any dictionary权限,而ts拥有。
SQL> conn test/test@otstest;Connected to Oracle Database10gEnterpriseEdition Release10.2.0.1.0 Connected as testSQL>SQL> create or replace procedure p_test_nc 2 is 3 i number; 4 begin 5 select count(*) 6 into i 7 from dba_objects; 8 9 dbms_output.put_line(to_char(i)); 10 end; 11 /Warning: Procedure created with compilation errors
检查报错信息,还是因为没有dba_objects的权限。
SQL> select * from user_errors;NAME TYPE SEQUENCE LINE POSITION TEXT ------------------------------- ---------- ---------- --------------------------------------P_TEST_NC PROCEDURE 1 7 8 PL/SQL: ORA-00942:表或视图不存在 P_TEST_NC PROCEDURE 2 5 3 PL/SQL: SQL Statement ignored
此时,我们如果在方法定义上加入authid current_user关键字,就可以将存储过程变化为调用者权限。
SQL> create or replace procedure p_test_nc 2 authid current_user 3 is 4 i number; 5 begin 6 select count(*) 7 into i 8 from dba_objects; 9 10 dbms_output.put_line(to_char(i)); 11 end; 12 /Warning: Procedure created with compilation errors
显然,还在因为dba_objects没有权限而报错,毕竟不管是什么体系,test目前是没有对象权限的。不过,为了实验成功,还是要让test能顺利编译过p_test_nc方法。
SQL> conn sys/acca@otstest as sysdba;Connected to Oracle Database10gEnterpriseEdition Release10.2.0.1.0Connected as SYSSQL> grant select any dictionary to test;Grant succeeded
切换回ts用户,注意此时他是拥有select any dictionary权限的。
SQL> conn ts/ts@otstest;Connected to Oracle Database10gEnterpriseEdition Release10.2.0.1.0Connected as tsSQL> exec test.p_test_nc;PL/SQL procedure successfully completedSQL> set serveroutput on size 1000;SQL> exec test.p_test_nc;53306PL/SQL procedure successfully completedSQL> select count(*) from dba_objects; COUNT(*)---------------------- 53306
此时,执行顺利成功。因为此时test和ts都拥有select any dictionary权限,所以即使在调用者权限下,也是会成功的。那么,如果我们收回ts上的权限,会如何呢?
SQL> conn sys/acca@otstest as sysdba;Connected to Oracle Database10gEnterpriseEdition Release10.2.0.1.0Connected as SYSSQL>revoke select any dictionary from ts; //权限回收Revoke succeededSQL> conn ts/ts@otstest;Connected to Oracle Database10gEnterpriseEdition Release10.2.0.1.0Connected as tsSQL> select count(*) from otstest;'select count(*) from otstest'ORA-00942:表或视图不存在SQL> exec test.p_test_nc;'begin test.p_test_nc; end;'ORA-00942:表或视图不存在ORA-06512:在"TEST.P_TEST_NC", line 6ORA-06512:在line 1
此时,就看出调用者权限的差异了。Test始终有dba_objects的权限,而ts在之后被取消了select any dictionary的权限。如果是所有者权限,ts调用p_test_nc是没有问题的。但是此时报错,说明此处使用的ts调用者权限。
调用者权限与role权限剥离现象
结合之前介绍的role权限剥离的现象,在调用者权限下,这种现象还有吗?我们下面的实验来证实。
继续上面实验的环境,用户ts已经失去了对dba_objects能访问的权限。Test用户拥有select any dictionary系统权限。方法p_test_nc调节为调用者权限。
--调用者权限与role剥离情况SQL> conn sys/acca@otstest as sysdba;Connected to Oracle Database10gEnterpriseEdition Release10.2.0.1.0Connected as SYSSQL> grant select_catalog_role to ts;Grant succeeded
对对象ts赋予select_catalog_role角色,该角色是能够访问dba_objects的,但是在所有者权限体系下,角色权限会被剔除。
SQL> conn ts/ts@otstest;Connected to Oracle Database10gEnterpriseEdition Release10.2.0.1.0Connected as tsSQL> select count(*) from dba_objects; COUNT(*)-------------------- 53306SQL> set serveroutput on size 1000;SQL> exec test.p_test_nc;53306PL/SQL procedure successfully completed
注意:我们发现,调用者权限p_test_nc方法应该使用调用者ts的权限。此时ts只有一个select_catalog_role角色权限与dba_objects有关联。可以猜想:在调用者方式下,非所有者调用时不会发生角色权限被剔除的现象。
SQL> conn sys/acca@otstest as sysdba; Connected to Oracle Database10gEnterpriseEdition Release10.2.0.1.0Connected as SYSSQL> revoke select any dictionary from test;Revoke succeededSQL> grant select_catalog_role to test;Grant succeededSQL> conn test/test@otstest;Connected to Oracle Database10gEnterpriseEdition Release10.2.0.1.0Connected as testSQL> select count(*) from dba_objects; COUNT(*)-------------------------- 53306SQL> set serveroutput on size 10000;SQL> exec p_test_nc;'begin p_test_nc; end;'ORA-06550:第1行,第7列:PLS-00905:对象TEST.P_TEST_NC无效ORA-06550:第1行,第7列:PL/SQL: Statement ignored
但是对于p_test_nc方法的所有者test来说,调用权限并没有解决role权限剔除的问题。依然存在存储过程角色剔除问题。
SQL> select * from dba_role_privs where grantee in ('TS','TEST');GRANTEE GRANTED_ROLE ------------------------------ -----------------------TEST RESOURCE TS CONNECT TEST SELECT_CATALOG_ROLE TS SELECT_CATALOG_ROLE TEST CONNECT TS RESOURCE 6 rows selected
通过上述的实验,我们可以得到如下的经验:
- 所有者权限和调用者权限是Oracle对存储过程等代码结构提供的独特权限组织模式。二者互为补充,应对不同的需求状况;
- 即使在调用者模式下,可以一定程度的避免role剔除现象,我们还是不建议使用role权限用户;
- 调用者权限体系在Oracle预定义方法、过程中大量采用,在进行开发的时候,如果遇到类似的问题和Bug,可以从调用者权限的角度去寻求解决方法;