yangtingkun
===========================================================
限制用户只能KILL本用户会话
===========================================================

前两天在论坛上看到一个帖子:http://www.itpub.net/thread-1143692-1-1.html。问题是如何授权使得用户可以KILL本用户的会话,而不能KILL其他用户的会话。


这个问题通过权限是没有办法控制的,因为允许KILL会话的权限就是ALTER SYSTEMALTER SYSTEM本身就是一个很强大的权限,可以对数据库实例进行设置。Oracle不但没有控制KILL哪些会话的权限,连单独KILL SESSION的权限都不存在。

而对于这种权限没有办法解决的问题,最好的处理方法就是通过存储过程将功能封装起来,然后将过程授权给用户:

SQL> CONN SYS@"172.25.198.224/TESTRAC" AS SYSDBA输入口令: ****已连接。
SQL> CREATE OR REPLACE PROCEDURE P_KILL_SESSION(P_USER IN VARCHAR2, P_SID IN VARCHAR2) AS
2 V_SQL VARCHAR2(32767);
3 BEGIN
4 SELECT 'ALTER SYSTEM KILL SESSION ''' || SID || ',' || SERIAL# || ''''
5 INTO V_SQL
6 FROM V$SESSION
7 WHERE USERNAME = P_USER
8 AND SID = P_SID;
9 EXECUTE IMMEDIATE V_SQL;
10 EXCEPTION
11 WHEN NO_DATA_FOUND THEN
12 RAISE_APPLICATION_ERROR(-20001,
13 'SID
' || P_SID || ' DOES NOT EXISTS, OR THE SESSION USER IS NOT ' || P_USER);
14 END;
15 /

过程已创建。

SQL> CREATE OR REPLACE PROCEDURE P_KILL_USER_SESSION(P_SID IN NUMBER)
2 AUTHID CURRENT_USER AS
3 V_USERNAME VARCHAR2(30);
4 V_SID NUMBER;
5 BEGIN
6 SELECT SYS_CONTEXT('USERENV', 'SESSION_USER'), SYS_CONTEXT('USERENV', 'SID')
7 INTO V_USERNAME, V_SID FROM DUAL;
8 IF P_SID != V_SID THEN
9 P_KILL_SESSION(V_USERNAME, P_SID);
10 ELSE
11 RAISE_APPLICATION_ERROR(-20000, 'CAN NOT KILL CURRENT SESSION!');
12 END IF;
13 END;
14 /

过程已创建。

SQL> CREATE USER U1 IDENTIFIED BY U1;

用户已创建。

SQL> GRANT CONNECT TO U1;

授权成功。

SQL> GRANT EXECUTE ON P_KILL_USER_SESSION TO U1;

授权成功。

过程P_KILL_SESSION用来KILL指定的会话,由于这个过程在SYS用户下创建,因此可以KILL任何会话,不过在KILL SESSION之前,过程检查输入的SIDUSERNAME是否相符,如果不相符则报错。

过程P_KILL_USER_SESSION是一个调用者权限过程,通过在这个过程中获取当前会话的SIDUSERNAME信息,并检查用户KILLSESSION是否与当前会话SID相同,如果相同则报错。

下面创建一个用户,并授予CONNECT角色,使得这个用户可以登陆数据库。这个用户除了CREATE SESSION权限外,没有其他的系统权限。下面将P_KILL_USER_SESSION过程授权给U1

并启动两个会话以U1连接到数据库:

SQL> CONN U1/U1@172.25.198.224/TESTRAC已连接。
SQL> SET SQLP 'SQL2> '
SQL2>

另一个连接:

SQL> CONN U1/U1@172.25.198.224/TESTRAC已连接。
SQL> SET SQLP 'SQL3> '

查询一下连接信息:

SQL> SELECT SID, USERNAME
2 FROM V$SESSION
3 WHERE MACHINE LIKE '%YTK%';

SID USERNAME
---------- ------------------------------
286 U1
291 U1
307 SYS

U1连查询V$SESSION的权限都没有,但是可以KILL另外一个以U1用户登陆的会话:

SQL2> SELECT * FROM V$SESSION;
SELECT * FROM V$SESSION
*
1 行出现错误:
ORA-00942:
表或视图不存在


SQL2> SELECT SYS_CONTEXT('USERENV', 'SID')
2 FROM DUAL;

SYS_CONTEXT('USERENV','SID')
----------------------------------------------------------------------------
286

SQL2> EXEC SYS.P_KILL_USER_SESSION(286)
BEGIN SYS.P_KILL_USER_SESSION(286); END;

* 1 行出现错误:
ORA-20000: CAN NOT KILL CURRENT SESSION!
ORA-06512:
"SYS.P_KILL_USER_SESSION", line 11
ORA-06512:
line 1


SQL2> EXEC SYS.P_KILL_USER_SESSION(307)
BEGIN SYS.P_KILL_USER_SESSION(307); END;

* 1 行出现错误:
ORA-20001: SID
307 DOES NOT EXISTS, OR THE SESSION USER IS NOT U1
ORA-06512:
"SYS.P_KILL_SESSION", line 12
ORA-06512:
"SYS.P_KILL_USER_SESSION", line 9
ORA-06512:
line 1


SQL2> EXEC SYS.P_KILL_USER_SESSION(291)

PL/SQL 过程已成功完成。

验证一下会话已经被KILL

SQL3> SELECT * FROM DUAL;
SELECT * FROM DUAL
*
1 行出现错误:
ORA-00028:
您的会话己被终止


SQL3>

这个问题并不复杂,不过刚好可以体现定义者存储过程和调用者存储过程的区别。

yangtingkun 发表于:2009.03.27 23:34 ::分类: ( ORACLE ) ::阅读:(1174次) :: 评论 (0)

发表评论
标题

在此添加评论
表情符号: smile laughing tongue angry crying sad wassat wink

称呼

邮箱地址(可选)

个人主页(可选)

 authimage


切换风格
新闻聚合
博客日历
文章归档...
最新发表...
最新评论...
最多阅读文章...
最多评论文章...
博客统计...
Blog信息
网站链接...