让普通用户可以kill自己用户下的session(转)

原文地址:http://space.itpub.net/?uid-4227-action-viewspace-itemid-580406

 

这个问题通过权限是没有办法控制的,因为允许KILL会话的权限就是ALTER SYSTEM。ALTER 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之前,过程检查输入的SID和USERNAME是否相符,如果不相符则报错。

过程P_KILL_USER_SESSION是一个调用者权限过程,通过在这个过程中获取当前会话的SID和USERNAME信息,并检查用户KILL的SESSION是否与当前会话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>

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

posted @ 2013-02-05 14:53  Alex-Zeng  阅读(1047)  评论(0编辑  收藏  举报