陈老师:1415968548 郑老师:2735197625 乐老师:354331153
客服热线:
19941464235/19906632509(微信同号)

客服微信

【Oracle OCP】19c 分析用户权限-DBMS_PRIVILEGE_CAPTURE

作者:炎燚小寶
发布时间:2023-12-19 09:24
浏览量:725

本文为云贝教育 刘峰 原创,请尊重知识产权,转发请注明出处,不接受任何抄袭、演绎和未经注明出处的转载。


在讨论数据库安全性时,“最小特权”的概念是一个常见的话题。它围绕着确保向用户授予最低级别的特权,以允许他们完成工作。任何不必要的特权都可能存在安全漏洞。

在开始一个新项目时,遵循最小特权思想可能相对简单。在现有系统上实现它要困难得多,因为这些系统已经被授予了过多的特权。

Oracle 12c引入了DBMS_PRIVILEGE_CAPTURE包,它允许您跟踪正在使用的特权,从而使执行特权分析变得更加简单,这反过来又允许您撤销不必要的特权并获得最少特权状态。



一、基础用法


为了使用DBMS_PRIVILEGE_CAPTURE包,您必须被授予CAPTURE_ADMIN角色。无论您试图监视什么,DBMS_PRIVILEGE_CAPTURE包的基本用法都是相同的。


以下可以确认sys是否拥有该角色

--查看用户被授权的角色
select * from dba_role_privs t where t.grantee='SYS' and t.granted_role='CAPTURE_ADMIN'

--查看角色拥有的权限
select * from dba_roles t where t.role='CAPTURE_ADMIN';


使用流程如下:

  1. 创建特权分析策略。(CREATE_CAPTURE)

  2. 启用。(ENABLE_CAPTURE)

  3. 等待所需的分析周期。

  4. 禁用特权分析策略。(DISABLE_CAPTURE)

  5. 分析结果。(GENERATE_RESULT和查询字典视图)

  6. 如果不再需要策略和记录的数据,请删除该策略。(DROP_CAPTURE)


分析运行之间的主要区别将基于对CREATE_CAPTURE过程的调用,这将在下面讨论。

启用和禁用捕获之间等待的时间是该过程中非常重要的一部分。你必须等待一段代表性的时间,否则你可能会错过一些重要的活动。例如,一些特权可能与不经常发生的任务相关联,比如年终作业。如果你没有在代表性时期取样,你可能会错误地得出某些特权是不必要的结论。


二、创建策略:CREATE_CAPTURE


1)CREATE_CAPTURE过程允许您创建具有不同粒度程度的特权分析策略。


2)所有策略都是在禁用状态下创建的。下面的代码给出了这两种方法的简单示例。

-- Connect to a privileged using in a PDB.
conn / as sysdba
alter session set container = pdb1;
-- 整体数据库 (type = G_DATABASE).
begin
  dbms_privilege_capture.create_capture(
    name        => 'db_pol',
    type        => dbms_privilege_capture.g_database
  );
end;
/
-- 一个或多个role (type = G_ROLE).
begin
  dbms_privilege_capture.create_capture(
    name        => 'role_pol',
    type        => dbms_privilege_capture.g_role,
    roles       => role_name_list('DBA', 'RESOURCE')
  );
end;
/

-- 用户定义的条件,比如用户是TEST (type = G_CONTEXT).
begin
  dbms_privilege_capture.create_capture(
    name        => 'cond_pol',
    type        => dbms_privilege_capture.g_context,
    condition   => 'sys_context(''userenv'', ''session_user'') = ''TEST'''
  );
end;
/

-- 角色和条件的组合 (type = G_ROLE_AND_CONTEXT).
begin
  dbms_privilege_capture.create_capture(
    name        => 'role_cond_pol',
    type        => dbms_privilege_capture.g_role_and_context,
    roles       => role_name_list('dba', 'resource'),
    condition   => 'sys_context(''userenv'', ''session_user'') in (''TEST'',''EMP'')'
  );
end;
/

3)dba_priv_capture视图显示有关现有特权捕获策略的信息。

column name format a15
column roles format a20
column context format a30
set linesize 100
select name,
       type,
       enabled,
       roles,
       context
from   dba_priv_captures
order by name;
NAME       TYPE       E ROLES         CONTEXT
--------------- ---------------- - -------------------- ------------------------------
cond_pol     CONTEXT     N             SYS_CONTEXT('USERENV', 'SESSIO
                               N_USER') = 'TEST'
db_pol      DATABASE     N
role_cond_pol   ROLE_AND_CONTEXT N ROLE_ID_LIST(4, 3)  SYS_CONTEXT('USERENV', 'SESSIO
                                                        N_USER') IN ('TEST','EMP')
role_pol     ROLE       N ROLE_ID_LIST(4, 3)
4 rows selected.
SQL>

三、启动策略:ENABLE_CAPTURE


ENABLE_CAPTURE过程用于启用捕获策略。通常,一次只能启用一个分析策略。例外情况是可以同时启用一个G_DATABASE和一个none G_DATABASE策略。

begin
  dbms_privilege_capture.enable_capture('db_pol');
  dbms_privilege_capture.enable_capture('cond_pol');
end;
/


四、禁用策略:DISABLE_CAPTURE


只要等待了一定的时间,就可以使用DISABLE_CAPTURE过程禁用捕获。

begin
  dbms_privilege_capture.disable_capture('db_pol');
  dbms_privilege_capture.disable_capture('cond_pol');
end;
/

五、收集信息:GENERATE_RESULTS


捕获完成后,应该使用GENERATE_RESULT过程将捕获的信息推送到数据字典视图。

begin
  dbms_privilege_capture.generate_result('db_pol');
end;
/


六、权限分析视图


Oracle 19c中提供了以下视图,允许您查询特权分析运行的结果。

DBA_PRIV_CAPTURES
DBA_USED_OBJPRIVS
DBA_USED_OBJPRIVS_PATH
DBA_USED_PRIVS
DBA_USED_PUBPRIVS
DBA_USED_SYSPRIVS
DBA_USED_SYSPRIVS_PATH
DBA_USED_USERPRIVS
DBA_USED_USERPRIVS_PATH
DBA_UNUSED_OBJPRIVS
DBA_UNUSED_OBJPRIVS_PATH
DBA_UNUSED_PRIVS
DBA_UNUSED_SYSPRIVS
DBA_UNUSED_SYSPRIVS_PATH
DBA_UNUSED_USERPRIVS
DBA_UNUSED_USERPRIVS_PATH


这些视图显示的信息将帮助您决定应该修改哪些授权和角色。


七、DROP_CAPTURE


一旦您的分析完成,您可以选择删除捕获的信息。只有禁用的策略才能被删除。

begin
  dbms_privilege_capture.drop_capture('cond_pol');
  dbms_privilege_capture.drop_capture('db_pol');
  dbms_privilege_capture.drop_capture('role_cond_pol');
  dbms_privilege_capture.drop_capture('role_pol');
end;
/


八、示例

以下是一个特权分析的例子。


1)通过赋予用户DBA和RESOURCE角色,创建具有高级特权的用户。

conn / as sysdba
alter session set container = pdb1;
create user priv_test_user identified by priv_test_user;
grant dba, resource to priv_test_user;

2)开始捕获针对该用户的这些角色的特权使用情况。

begin
  dbms_privilege_capture.create_capture(
    name        => 'dba_res_user_pol',
    type        => dbms_privilege_capture.g_role_and_context,
    roles       => role_name_list('DBA', 'RESOURCE'),
    condition   => 'sys_context(''userenv'', ''session_user'') = ''PRIV_TEST_USER'''
  );
  dbms_privilege_capture.enable_capture(
    name        => 'dba_res_user_pol'
  );
end;
/

3)使用PRIV_TEST_USER用户执行一些操作。

conn priv_test_user/priv_test_user@pdb1
create table tab1 (
  id number,
  description varchar2(50),
  constraint tab1_px primary key (id)
);

create sequence tab1_seq;

create view tab1_view as
select * from tab1;

insert into tab1
select level, 'Description of ' || to_char(level)
from   dual
connect by level <= 5; commit; select name from v$database;

4)禁用捕获过程并将结果推送到数据字典。

conn / as sysdba
alter session set container = pdb1;
begin
  dbms_privilege_capture.disable_capture(
    name        => 'dba_res_user_pol'
  );
  dbms_privilege_capture.generate_result(
    name        => 'dba_res_user_pol'
  );
end;
/

5)通过查询数据字典来检查捕获期间使用的特权。

在捕获期间使用了哪些系统特权?我们可以从DBA_USED_PRIVS、DBA_USED_SYSPRIVS或DBA_USED_SYSPRIVS_PATH视图获取该信息。

column username format a20
column sys_priv format a20
select username, sys_priv
from   dba_used_sysprivs
where  capture = 'dba_res_user_pol'
order by username, sys_priv;
USERNAME        SYS_PRIV
-------------------- --------------------
PRIV_TEST_USER     CREATE ANY INDEX
PRIV_TEST_USER     CREATE SEQUENCE
PRIV_TEST_USER     CREATE SESSION
PRIV_TEST_USER     CREATE TABLE
PRIV_TEST_USER     CREATE VIEW
5 rows selected.

除了CREATE ANY INDEX特权之外,这些都是直接的。这需要进一步调查,但在许多情况下,这只是Oracle的一个可以忽略的怪癖。如果您有能力创建表,那么您也有能力为这些表建立索引。因此,在大多数情况下实际上并不需要使用CREATE ANY INDEX特权。


6这些特权是如何授予用户的?我们可以从DBA_USED_SYSPRIVS_PATH视图获取该信息。

column username format a20
column used_role format a30
column sys_priv format a20
column path format a50
set linesize 200
select username, sys_priv, used_role, path
from   dba_used_sysprivs_path
where  capture = 'dba_res_user_pol'
order by username, sys_priv;
USERNAME       SYS_PRIV       USED_ROLE            PATH
-------------------- -------------------- ------------------------------ --------------------------------------------------
PRIV_TEST_USER    CREATE ANY INDEX  IMP_FULL_DATABASE        GRANT_PATH('PRIV_TEST_USER', 'DBA', 'IMP_FULL_DATA
                                      BASE')
PRIV_TEST_USER    CREATE ANY INDEX  IMP_FULL_DATABASE        GRANT_PATH('PRIV_TEST_USER', 'DBA', 'DATAPUMP_IMP_
                                      FULL_DATABASE', 'IMP_FULL_DATABASE')
PRIV_TEST_USER    CREATE SEQUENCE   OLAP_DBA            GRANT_PATH('PRIV_TEST_USER', 'DBA', 'OLAP_DBA')
PRIV_TEST_USER    CREATE SESSION    EM_EXPRESS_BASIC        GRANT_PATH('PRIV_TEST_USER', 'DBA', 'EM_EXPRESS_AL
                                      L', 'EM_EXPRESS_BASIC')
PRIV_TEST_USER    CREATE TABLE     DATAPUMP_EXP_FULL_DATABASE   GRANT_PATH('PRIV_TEST_USER', 'DBA', 'DATAPUMP_EXP_
                                      FULL_DATABASE', 'EXP_FULL_DATABASE')
PRIV_TEST_USER    CREATE TABLE     DATAPUMP_EXP_FULL_DATABASE   GRANT_PATH('PRIV_TEST_USER', 'DBA', 'DATAPUMP_EXP_
                                      FULL_DATABASE')
PRIV_TEST_USER    CREATE VIEW     DBA               GRANT_PATH('PRIV_TEST_USER', 'DBA')
7 rows selected.

因此,特权来自各种角色,但是查看PATH列的输出,所有特权都来自DBA角色的授予。

7需要哪些对象权限?我们可以从DBA_USED_PRIVS、DBA_USED_OBJPRIVS或DBA_USED_OBJPRIVS_PATH视图中获得这些信息。

column username format a20
column obj_priv format a8
column object_owner format a15
column object_name format a20
column object_type format a11
select username, obj_priv, object_owner, object_name, object_type
from   dba_used_objprivs
where  capture = 'dba_res_user_pol';
USERNAME       OBJ_PRIV OBJECT_OWNER   OBJECT_NAME      OBJECT_TYPE
-------------------- -------- --------------- -------------------- -----------
PRIV_TEST_USER    SELECT  SYS       V_$DATABASE      VIEW
1 row selected.

8这些特权是如何授予用户的?我们可以从DBA_USED_OBJPRIVS_PATH视图获取该信息。

column username format a20
column obj_priv format a8
column object_owner format a15
column object_name format a20
column used_role format a20
column path format a30
set linesize 200
select username, obj_priv, object_owner, object_name, used_role, path
from   dba_used_objprivs_path
where  capture = 'dba_res_user_pol';
USERNAME             OBJ_PRIV OBJECT_OWNER    OBJECT_NAME          USED_ROLE            PATH
-------------------- -------- --------------- -------------------- -------------------- ------------------------------
PRIV_TEST_USER       SELECT   SYS             V_$DATABASE          SELECT_CATALOG_ROLE  GRANT_PATH('PRIV_TEST_USER', '
                                                                                        DBA', 'SELECT_CATALOG_ROLE')
PRIV_TEST_USER       SELECT   SYS             V_$DATABASE          SELECT_CATALOG_ROLE  GRANT_PATH('PRIV_TEST_USER', '
                                                                                        DBA', 'EXP_FULL_DATABASE', 'SE
                                                                                        LECT_CATALOG_ROLE')
PRIV_TEST_USER       SELECT   SYS             V_$DATABASE          SELECT_CATALOG_ROLE  GRANT_PATH('PRIV_TEST_USER', '
                                                                                        DBA', 'IMP_FULL_DATABASE', 'SE
                                                                                        LECT_CATALOG_ROLE')
PRIV_TEST_USER       SELECT   SYS             V_$DATABASE          SELECT_CATALOG_ROLE  GRANT_PATH('PRIV_TEST_USER', '
                                                                                        DBA', 'DATAPUMP_EXP_FULL_DATAB
                                                                                        ASE', 'EXP_FULL_DATABASE', 'SE
                                                                                        LECT_CATALOG_ROLE')
PRIV_TEST_USER       SELECT   SYS             V_$DATABASE          SELECT_CATALOG_ROLE  GRANT_PATH('PRIV_TEST_USER', '
                                                                                        DBA', 'DATAPUMP_IMP_FULL_DATAB
                                                                                        ASE', 'EXP_FULL_DATABASE', 'SE
                                                                                        LECT_CATALOG_ROLE')
PRIV_TEST_USER       SELECT   SYS             V_$DATABASE          SELECT_CATALOG_ROLE  GRANT_PATH('PRIV_TEST_USER', '
                                                                                        DBA', 'DATAPUMP_IMP_FULL_DATAB
                                                                                        ASE', 'IMP_FULL_DATABASE', 'SE
                                                                                        LECT_CATALOG_ROLE')
PRIV_TEST_USER       SELECT   SYS             V_$DATABASE          SELECT_CATALOG_ROLE  GRANT_PATH('PRIV_TEST_USER', '
                                                                                        DBA', 'EM_EXPRESS_ALL', 'EM_EX
                                                                                        PRESS_BASIC', 'SELECT_CATALOG_
                                                                                        ROLE')
7 rows selected.


同样,这些特权来自不同的角色,但是查看PATH列的输出,所有特权都来自DBA角色的授予。


9由此我们能得出什么结论?



10所以解决方法似乎很简单。创建一个自定义角色来应用任何必要的特权,然后撤销DBA和RESOURCE角色。

conn / as sysdba
alter session set container = pdb1;
create role custom_role;
grant create sequence to custom_role;
grant create session to custom_role;
grant create table to custom_role;
grant create view to custom_role;
grant select on sys.v_$database to custom_role;
grant custom_role to priv_test_user;
revoke dba, resource from priv_test_user;

11分析完成后,我们可以选择从数据字典中删除捕获的信息。

 
begin
  dbms_privilege_capture.drop_capture(
    name        => 'dba_res_user_pol'
  );
end;
/