暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle 23c 新特性:只读用户

小小亮 2024-12-03
270

Oracle 在 23c 版本中增加了创建只读用户的功能。这可以通过使用新的 ALTER USER 或 CREATE USER 语法,并包含 READ ONLY 或 READ WRITE 子句来实现。让我们通过一个简单的演示来了解这个新特性。首先,连接到 23c 数据库:

SQL> sho user USER is "SYS" SQL> select banner from v$version; BANNER -------------------------------------------------------------------------------- Oracle Database 23c Free, Release 23.0.0.0.0 - Developer-Release SQL>

接下来,我们可以创建一个示例用户 VV,并授予一些进行读和写的权限:

SQL> create user vv identified by vv; User created. SQL> grant create session to vv; Grant succeeded. SQL> grant select,insert on orablog.customer to vv; Grant succeeded. SQL> grant execute on orablog.custa to vv; Grant succeeded. SQL>

然后,以新用户身份连接并测试我们可以进行读和写操作:

SQL> connect vv/vv@//192.168.56.18:1521/freepdb1 Connected. SQL> -- test SQL> select count(*) from orablog.customer; COUNT(*) ---------- 3 SQL> select * from orablog.customer; FULLNAME FIRSTNAME ------------------------------ ------------------------------ LASTNAME ------------------------------ Pete Finnigan Pete Finnigan Zulia Finnigan Zulia Finnigan Eric Finnigan Eric Finnigan SQL> insert into orablog.customer (fullname,firstname,lastname) values ('EmilFinnigan','Emil','Finnigan'); 1 row created. SQL> set serveroutput on SQL> exec orablog.custa('Finnigan'); name:=[Pete Finnigan] name:=[Zulia Finnigan] PL/SQL procedure successfully completed. SQL>

现在,我们以 SYS 用户身份连接并改变我们的示例用户 VV 为只读:

SQL> connect sys/oracle@//192.168.56.18:1521/freepdb1 as sysdba Connected. SQL> alter user vv read only; User altered. SQL>

出于兴趣,这个只读设置也可以在用户创建时完成:

SQL> sho user USER is "SYS" SQL> create user vx identified by vx read only; User created. SQL>

以 VV 用户身份连接并重新执行 select 语句:

SQL> connect vv/vv@//192.168.56.18:1521/freepdb1 Connected. SQL> select count(*) from orablog.customer; COUNT(*) ---------- 4 SQL> select * from orablog.customer; FULLNAME FIRSTNAME ------------------------------ ------------------------------ LASTNAME ------------------------------ Pete Finnigan Pete Finnigan Zulia Finnigan Zulia Finnigan EmilFinnigan Emil Finnigan FULLNAME FIRSTNAME ------------------------------ ------------------------------ LASTNAME ------------------------------ Eric Finnigan Eric Finnigan SQL>

这些操作都是正确的。如果我们尝试一个插入语句,VV 有权限执行:

SQL> insert into orablog.customer(fullname,firstname,lastname) values ('TestUser','Test','User'); insert into orablog.customer(fullname,firstname,lastname) values ('TestUser','Test','User') * ERROR at line 1: ORA-28194: Can perform read operations only SQL>

所以,很好,只读功能按预期工作,即使我们有权限在该表上执行插入操作,我们也不能执行 INSERT。

现在尝试 PL/SQL 过程:

SQL> set serveroutput on SQL> exec orablog.custa('Finnigan'); name:=[Pete Finnigan] name:=[Zulia Finnigan] PL/SQL procedure successfully completed. SQL>

嗯,我们只对 ORABLOG.CUSTOMER 进行读操作,而不是插入,但我们执行了 PL/SQL。让我们尝试一个不同的例子:

SQL> exec dbms_output.put_line('Test test'); Test test PL/SQL procedure successfully completed. SQL>

嗯,我们可以运行 PL/SQL,所以对我来说它不仅仅是只读,我们可以执行 EXECUTE?

我们可以将普通用户设置为只读吗?连接到 PDB 并尝试:

SQL> connect sys/oracle@//192.168.56.18:1521/freepdb1 as sysdba Connected. SQL> alter session set container=cdb$root; Session altered. SQL> create user c##vv identified by c##vv read only; create user c##vv identified by c##vv read only * ERROR at line 1: ORA-28192: Enabling or disabling read-only property is not allowed on a common user. SQL>

所以我们不能给普通用户添加只读属性,尽管一个只读的普通用户可能很有用。

我们可以通过 PL/SQL 执行插入操作吗?

SQL> sho user USER is "SYS" SQL> grant create procedure to vv; Grant succeeded. SQL> connect vv/vv@//192.168.56.18:1521/freepdb1 Connected. SQL> create procedure run as 2 begin 3 insert into orablog.customer(fullname,firstname,lastname) values ('TestName','Test','Name'); 4 end; 5 / create procedure run as * ERROR at line 1: ORA-28194: Can perform read operations only SQL>

非常有趣。我们不能创建一个过程,因为我们是只读的,因为过程被写入数据库,违反了只读规则。我们可以创建一个动态过程吗?

SQL> get dyn.sql 1 -- test dyn proceudre to test read only 2 -- -------------------------------------------------- 3 -- Create the "procedure" 4 -- -------------------------------------------------- 5 var lv_str varchar2(2000); 6 var curnum number; 7 -- null the string 8 exec :lv_str:=''; 9 declare 10 begin 11 :curnum:=dbms_sql.open_cursor; 12 dbms_sql.parse(:curnum,'declare bv varchar2(2000):=:ipstr; begin dbms_output.put_line(bv);end;',dbms_sql.native); 13 end; 14 / 15 print curnum 16 -- ------------------------------------------------------- 17 -- end of declaring the "procedure" 18 -- ------------------------------------------------------- 19 -- ------------------------------------------------------- 20 -- Call the dynamic procedure 21 -- ------------------------------------------------------- 22 -- prime the string to print it 23 exec :lv_str:='hello world'; 24 declare 25 n number; 26 begin 27 -- bind the variable 28 dbms_sql.bind_variable(:curnum,':ipstr',:lv_str); 29 n:=dbms_sql.execute(:curnum); 30 end; 31 / 32 -- -------------------------------------------------------- 33 -- End of dynamic procedure call 34* -- -------------------------------------------------------- 35 . SQL> SQL> @dyn PL/SQL procedure successfully completed. PL/SQL procedure successfully completed. CURNUM ---------- 1923939752 PL/SQL procedure successfully completed. hello world PL/SQL procedure successfully completed. SQL>

所以我们可以绕过创建过程的限制,但我们能在这个过程里执行插入操作吗?让我们修改 dyn.sql:

SQL> get dyn.sql 1 -- test dyn proceudre to test read only 2 -- -------------------------------------------------- 3 -- Create the "procedure" 4 -- -------------------------------------------------- 5 var curnum number; 6 declare 7 begin 8 :curnum:=dbms_sql.open_cursor; 9 dbms_sql.parse(:curnum,'begin insert into orablog.customer(fullname,firstname,lastname) values(''TestUser'',''Test'',''User'');end;',dbms_sql.native); 10 end; 11 / 12 print curnum 13 -- ------------------------------------------------------- 14 -- end of declaring the "procedure" 15 -- ------------------------------------------------------- 16 -- ------------------------------------------------------- 17 -- Call the dynamic procedure 18 -- ------------------------------------------------------- 19 declare 20 n number; 21 begin 22 n:=dbms_sql.execute(:curnum); 23 end; 24 / 25 -- -------------------------------------------------------- 26 -- End of dynamic procedure call 27* -- -------------------------------------------------------- 28 . SQL> @dyn declare * ERROR at line 1: ORA-29471: DBMS_SQL access denied ORA-06512: at "SYS.DBMS_SQL", line 1169 ORA-06512: at line 4 CURNUM ---------- declare * ERROR at line 1: ORA-29471: DBMS_SQL access denied ORA-06512: at "SYS.DBMS_SQL", line 1792 ORA-06512: at line 4 SQL>

不,我们不能通过动态PL/SQL 代码块执行插入操作。ORA-29471 是一个安全问题,因此被阻止。

为用户 VV 关闭只读属性以展示如何撤销:

SQL> sho user USER is "SYS" SQL> alter user vv read write; User altered. SQL>

在我们使用户 VV 变为可读写之后,再次尝试动态过程:

SQL> connect vv/vv@//192.168.56.18:1521/freepdb1 Connected. SQL> @dyn PL/SQL procedure successfully completed. CURNUM ---------- 1166850649 PL/SQL procedure successfully completed. SQL>

关于用户只读状态的存储。我们需要能够检查数据库并测试哪些用户是只读的:

SQL> desc dba_users Name Null? Type ----------------------------------------- -------- ---------------------------- USERNAME NOT NULL VARCHAR2(128) USER_ID NOT NULL NUMBER PASSWORD VARCHAR2(4000) ACCOUNT_STATUS NOT NULL VARCHAR2(32) LOCK_DATE DATE EXPIRY_DATE DATE DEFAULT_TABLESPACE NOT NULL VARCHAR2(30) TEMPORARY_TABLESPACE NOT NULL VARCHAR2(30) LOCAL_TEMP_TABLESPACE VARCHAR2(30) CREATED NOT NULL DATE PROFILE NOT NULL VARCHAR2(128) INITIAL_RSRC_CONSUMER_GROUP VARCHAR2(128) EXTERNAL_NAME VARCHAR2(4000) PASSWORD_VERSIONS VARCHAR2(17) EDITIONS_ENABLED VARCHAR2(1) AUTHENTICATION_TYPE VARCHAR2(8) PROXY_ONLY_CONNECT VARCHAR2(1) COMMON VARCHAR2(3) LAST_LOGIN TIMESTAMP(9) WITH TIME ZONE ORACLE_MAINTAINED VARCHAR2(1) INHERITED VARCHAR2(3) DEFAULT_COLLATION VARCHAR2(100) IMPLICIT VARCHAR2(3) ALL_SHARD VARCHAR2(3) EXTERNAL_SHARD VARCHAR2(3) PASSWORD_CHANGE_DATE DATE MANDATORY_PROFILE_VIOLATION VARCHAR2(3) PROTECTED VARCHAR2(3) READ_ONLY VARCHAR2(3) DICTIONARY_PROTECTED VARCHAR2(3) SQL>

现在我们可以检查 READ_ONLY 列,看看数据库中哪些用户是只读的:

SQL> select username from dba_users where read_only='YES'; USERNAME -------------------------------------------------------------------------------- VX SQL>

这是正确的,因为我们之前将 VV 设置为可读写,并将 VX 创建为只读。

该标志存储在 SYS.USER$ 的 SPARE1 列中作为一个位标志:

decode(bitand(u.spare1, 524288), 524288, 'YES', 'NO'), -- READ_ONLY

总结来说,只读允许 SELECT 并阻止 INSERT/UPDATE 和 DELETE,但我们仍然可以执行 EXECUTE,只要 PL/SQL 没有尝试更改数据。我不知道在用户是只读时,“可以/不可以”在 PL/SQL 中执行什么操作。更多的测试将能进一步展示这一点。

这是一个阻止更改的有用特性,但如果攻击者想要从你的数据库中窃取所有个人信息或信用卡信息,那么他不需要更改,他只需要读取!

原文标题:Read Only Users in 23c
原文作者:Pete Finnigan
原文链接:http://www.petefinnigan.com/weblog/archives/00001521.htm

最后修改时间:2024-12-03 10:01:20
文章转载自小小亮,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论