This blog comes to complete the excellent blog written by my colleague Gregory Steulet on the same topic.
SQL FIREWALL is a new security layer integrated into Oracle Database 23c.
First, we create a admin user for which we grant it a new admin privilege “sql_firewall_admin”:
SQL> drop user if exists lfeadmin cascade;
User dropped.
SQL>
SQL> create user lfeadmin identified by lfeadmin;
User created.
SQL> grant create session to lfeadmin;
Grant succeeded.
SQL> grant sql_firewall_admin to lfeadmin;
Grant succeeded.
We enable the SQL FIREWALL:
SQL> prompt ENABLE SQL FIREWALL
ENABLE SQL FIREWALL
SQL> pause
SQL> conn lfeadmin/lfeadmin@//localhost:1521/freepdb1
Connected.
SQL> exec dbms_sql_firewall.enable;
PL/SQL procedure successfully completed.
SQL>
SQL> prompt CHECK THE STATUS OF SQL FIREWALL
CHECK THE STATUS OF SQL FIREWALL
SQL> pause
SQL> select status from dba_sql_firewall_status;
STATUS
--------
ENABLED
We create a capture process on the user LFE:
SQL> prompt CREATE CAPTURE FOR USER LFE
CREATE CAPTURE FOR USER LFE
SQL> pause
SQL> begin
2 dbms_sql_firewall.create_capture (
3 username => 'LFE',
4 top_level_only => false,
5 start_capture => true);
6 end;
7 /
PL/SQL procedure successfully completed.
We execute some sql from the user LFE:
SQL> conn LFE/LFE4DBIXCHANGE2023@//localhost:1521/freepdb1
Connected.
SQL> start demo_sql_firewall_load.sql
SQL> set echo on
SQL> set linesize 2000
SQL> prompt SESSION 1 - GET SID
SESSION 1 - GET SID
SQL> pause
SQL> SELECT SYS_CONTEXT ('USERENV', 'SID') FROM DUAL;
SYS_CONTEXT('USERENV','SID')
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
44
SQL> prompt SESSION 1 - UPDATE PRICE FOR PRODUCT A1 --> PRICE = PRICE+10
SESSION 1 - UPDATE PRICE FOR PRODUCT A1 --> PRICE = PRICE+10
SQL> pause
SQL> select price from products where product='A1';
PRICE
----------
1629
SQL> update products set price = price+10 where product= 'A1';
1 row updated.
SQL> select price from products where product='A1';
PRICE
----------
1629
SQL>
We stop the capture and we check the capture logs:
SQL> prompt STOP THE CAPTURE
STOP THE CAPTURE
SQL> pause
SQL> exec dbms_sql_firewall.stop_capture('LFE');
PL/SQL procedure successfully completed.
SQL>
SQL> prompt CHECK CAPTURE LOGS
CHECK CAPTURE LOGS
SQL> pause
SQL> set linesize 150 pagesize 40
SQL> column command_type format a12
SQL> column current_user format a15
SQL> column client_program format a45
SQL> column os_user format a10
SQL> column ip_address format a10
SQL> column sql_text format a30
SQL>
SQL> select command_type,
2 current_user,
3 client_program,
4 os_user,
5 ip_address,
6 sql_text
7 from dba_sql_firewall_capture_logs
8 where username = 'LFE';
COMMAND_TYPE CURRENT_USER CLIENT_PROGRAM OS_USER IP_ADDRESS SQL_TEXT
------------ --------------- --------------------------------------------- --
SELECT LFE sqlplus@db23c (TNS V1-V3) oracle 127.0.0.1 SELECT SYS_CONTEXT (:"SYS_B_0",:"SYS_B_1") FROM DUAL
SELECT LFE sqlplus@db23c (TNS V1-V3) oracle 127.0.0.1 SELECT PRICE FROM PRODUCTS WHERE PRODUCT=:"SYS_B_0"
UPDATE LFE sqlplus@db23c (TNS V1-V3) oracle 127.0.0.1 UPDATE PRODUCTS SET PRICE=PRICE +:"SYS_B_0" WHERE PRODUCT=:"SYS_B_1"
Now we generate an allow list based on the capture logs:
SQL> exec dbms_sql_firewall.generate_allow_list ('LFE');
PL/SQL procedure successfully completed.
SQL>
SQL> prompt CHECK THE ALLOW LIST AND NEW DATA DICTIONARY VIEWS
CHECK THE ALLOW LIST AND NEW DATA DICTIONARY VIEWS
SQL> pause
SQL> column username format a20
SQL> select * from dba_sql_firewall_allowed_ip_addr where username = 'LFE';
USERNAME IP_ADDRESS
-------------------- ----------
LFE 127.0.0.1
SQL>
SQL> column os_program format a50
SQL> select * from dba_sql_firewall_allowed_os_prog where username = 'LFE';
USERNAME OS_PROGRAM
-------------------- --------------------------------------------------
LFE sqlplus@db23c (TNS V1-V3)
SQL>
SQL> column os_user format a10
SQL> select * from dba_sql_firewall_allowed_os_user where username = 'LFE';
USERNAME OS_USER
-------------------- ----------
LFE oracle
SQL>
SQL> column sql_text format A50
SQL> select current_user,sql_text from dba_sql_firewall_allowed_sql where username = 'LFE';
CURRENT_USER SQL_TEXT
--------------- --------------------------------------------------
LFE UPDATE PRODUCTS SET PRICE=PRICE +:"SYS_B_0" WHERE
PRODUCT=:"SYS_B_1"
LFE SELECT PRICE FROM PRODUCTS WHERE PRODUCT=:"SYS_B_0
"
LFE SELECT SYS_CONTEXT (:"SYS_B_0",:"SYS_B_1") FROM DU
AL
The allow list stores the sql statement captures plus his context (IP ADDRESS, OS_PROGRAM, OS_USER).
We check this allow list and decides which sql statement / context authorized or un-authorized to be executed and we enable the allow list, we use the option “dbms_sql_firewall.enforfe_all” to authorize all : the sql statement plus the context. There are different list of options.
SQL> begin
2 dbms_sql_firewall.enable_allow_list (
3 username => 'LFE',
4 enforce => dbms_sql_firewall.enforce_all,
5 block => true);
6 end;
7 /
PL/SQL procedure successfully completed.
SQL> select username,
status,
top_level_only,
enforce,
block
from dba_sql_firewall_allow_lists
where username='LFE';
USERNAME STATUS TOP_LEVEL_ONLY ENFORCE BLOCK
-------------------- -------- -------------- --------------- --------------
LFE ENABLED N ENFORCE_ALL Y
Now, SQL which are in the allow list are authorized:
SQL> select price from products where product='A1';
PRICE
----------
1629
But SQL which are not in the allow list are un-authorized:
SQL> select price,product from products where product='A1';
select price,product from products where product='A1'
*
ERROR at line 1:
ORA-47605: SQL Firewall violation
We check the sql firewall violation log table:
select sql_text,
firewall_action,
ip_address,
cause,
occurred_at
from dba_sql_firewall_violations
where username = 'LFE';
SQL_TEXT
--------------------------------------------------------------------------------
FIREWAL IP_ADDRESS CAUSE
------- ------------------------------------------------ --------------------
OCCURRED_AT
---------------------------------------------------------------------------
SELECT PRICE,PRODUCT FROM PRODUCTS WHERE PRODUCT=:"SYS_B_0"
Blocked 127.0.0.1 SQL violation
27-SEP-23 06.30.31.875532 PM +00:00
SQL>