客服微信
本文为云贝教育 刘峰 原创,请尊重知识产权,转发请注明出处,不接受任何抄袭、演绎和未经注明出处的转载。
在讨论数据库安全性时,“最小特权”的概念是一个常见的话题。它围绕着确保向用户授予最低级别的特权,以允许他们完成工作。任何不必要的特权都可能存在安全漏洞。
在开始一个新项目时,遵循最小特权思想可能相对简单。在现有系统上实现它要困难得多,因为这些系统已经被授予了过多的特权。
Oracle 12c引入了DBMS_PRIVILEGE_CAPTURE包,它允许您跟踪正在使用的特权,从而使执行特权分析变得更加简单,这反过来又允许您撤销不必要的特权并获得最少特权状态。
基础用法
CREATE_CAPTURE
ENABLE_CAPTURE
DISABLE_CAPTURE
GENERATE_RESULT
Privilege Analysis Views
DROP_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';
使用流程如下:
创建特权分析策略。(CREATE_CAPTURE)
启用。(ENABLE_CAPTURE)
等待所需的分析周期。
禁用特权分析策略。(DISABLE_CAPTURE)
分析结果。(GENERATE_RESULT和查询字典视图)
如果不再需要策略和记录的数据,请删除该策略。(DROP_CAPTURE)
分析运行之间的主要区别将基于对CREATE_CAPTURE过程的调用,这将在下面讨论。
启用和禁用捕获之间等待的时间是该过程中非常重要的一部分。你必须等待一段代表性的时间,否则你可能会错过一些重要的活动。例如,一些特权可能与不经常发生的任务相关联,比如年终作业。如果你没有在代表性时期取样,你可能会错误地得出某些特权是不必要的结论。
1)CREATE_CAPTURE过程允许您创建具有不同粒度程度的特权分析策略。
G_DATABASE:分析数据库上除SYS用户外的所有特权使用情况。不需要ROLES和CONDITION参数。
G_ROLE:分析roles参数中指定的角色使用的所有权限。使用ROLE_NAME_LIST函数指定角色。
G_CONTEXT:当CONDITION参数中指定的布尔表达式计算结果为TRUE时,分析所有特权的使用情况。条件可以包括对SYS_CONTEXT调用的组合。
G_ROLE_AND_CONTEXT:分析ROLES和CONDITION条件都为真时的所有特权使用情况。
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过程用于启用捕获策略。通常,一次只能启用一个分析策略。例外情况是可以同时启用一个G_DATABASE和一个none G_DATABASE策略。
begin dbms_privilege_capture.enable_capture('db_pol'); dbms_privilege_capture.enable_capture('cond_pol'); end; /
只要等待了一定的时间,就可以使用DISABLE_CAPTURE过程禁用捕获。
begin dbms_privilege_capture.disable_capture('db_pol'); dbms_privilege_capture.disable_capture('cond_pol'); end; /
捕获完成后,应该使用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
这些视图显示的信息将帮助您决定应该修改哪些授权和角色。
一旦您的分析完成,您可以选择删除捕获的信息。只有禁用的策略才能被删除。
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)由此我们能得出什么结论?
所使用的所有特权都是通过DBA角色授予的,因此不需要直接特权。
除了CREATE ANY INDEX特权(需要在实际情况中进一步研究)之外,所使用的所有特权都是非常基本的,因此该用户实际上不需要DBA和RESOURCE角色。
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; /