0

Oracle 23c : se protéger des attaques par injections SQL grâce à SQL Firewall

twitterlinkedinmail

  Bonjour à toutes et tous et bonne année 2024 !

Nous débutons cette nouvelle année avec un article, une fois de plus, en lien avec la sécurité ! C’est un sujet que nous avons grandement abordé au cours de l’année 2023, sur les SGBD SQL Server et PostgreSQL.
Pour débuter 2024 dans la même voie, je vous propose une présentation de la brique SQL Firewall présente dans la version Oracle 23c.

 

Pour qualifier et tester les nouveautés Oracle 23c, nous avons la possibilité de télécharger et installer l’édition FREE Edition qui, de plus, est utilisable “on prem”.

Ce tableau, fourni par Oracle, nous montre les différentes offres présentes :

 

Vous remarquerez qu’il n’y a, à ce jour, ni Standard Edition 2, ni offre Enterprise Edition on prem.

Une note Oracle indique cependant une éventuelle prise en charge de cette version dès le premier semestre 2024 sous Linux x86-64

Release Schedule of Current Database Releases (Doc ID 742060.1)

Nous suivrons plus précisément les informations à ce sujet au cour de ce début d’année.

 

Installation Oracle 23c FREE Edition

 

Nous disposons d’une VM EC2 de type Rocky Linux 8.6 pour tester la nouvelle version Oracle 23c

[oracle@ etc]$ cat os-release
NAME="Rocky Linux"
VERSION="8.6 (Green Obsidian)"
ID="rocky"
ID_LIKE="rhel centos fedora"
VERSION_ID="8.6"
PLATFORM_ID="platform:el8"
PRETTY_NAME="Rocky Linux 8.6 (Green Obsidian)"
ANSI_COLOR="0;32"
CPE_NAME="cpe:/o:rocky:rocky:8:GA"
HOME_URL="https://rockylinux.org/"
BUG_REPORT_URL="https://bugs.rockylinux.org/"
ROCKY_SUPPORT_PRODUCT="Rocky Linux"
ROCKY_SUPPORT_PRODUCT_VERSION="8"
REDHAT_SUPPORT_PRODUCT="Rocky Linux"
REDHAT_SUPPORT_PRODUCT_VERSION="8"

L’installation de la version Oracle 23c Free Edition sur un fork Red Hat est on ne peut plus simple :

Une fois téléchargés et copiés vers le serveur linux, passer à l’installation via rpm sous “root

 

— Le package de preinstallation permettant la configuration OS propre à Oracle.

[root@ ~]# rpm -iv /tmp/oracle-database-preinstall-23c-1.0-0.5.el8.x86_64.rpm
warning: /tmp/oracle-database-preinstall-23c-1.0-0.5.el8.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID ad986da3: NOKEY
Verifying packages...
Preparing packages...
oracle-database-preinstall-23c-1.0-0.5.el8.x86_64

 

— Puis le package d’installation du moteur Oracle 23c. Attention, l’installation va se faire dans un répertoire “/opt”. Prévoir une place d’au moins 8Go sur ce montage.

[root@ ~]# rpm -iv /tmp/oracle-database-free-23c-1.0-1.el8.x86_64.rpm
warning: /tmp/oracle-database-free-23c-1.0-1.el8.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID ad986da3: NOKEY
Verifying packages...
Preparing packages...
oracle-database-free-23c-1.0-1.x86_64
[INFO] Executing post installation scripts...
[INFO] Oracle home installed successfully and ready to be configured.
To configure Oracle Database Free, optionally modify the parameters in '/etc/sysconfig/oracle-free-23c.conf' and then run '/etc/init.d/oracle-free-23c configure' as root.

 

Valider l’installation des packages

[root@ ~]# rpm -qav | grep -i oracle
oracle-database-preinstall-23c-1.0-0.5.el8.x86_64
oracle-database-free-23c-1.0-1.x86_64

 

[root@ ~]# ls /opt/oracle/product/23c/dbhomeFree/
addnode clone ctx deinstall env.ora instantclient jdk LICENSE nls OPatch ord plsql R root.sh slax sqlplus usm
assistants crs cv demo has inventory jlib md odbc opmn oss precomp racg runInstaller sqlcl srvm utl
bin crypto data diagnostics hs javavm ldap mgw olap oracore oui python rdbms schagent.conf sqlj ss_oracle.sdo.acl xdk
cfgtoollogs css dbs dv install jdbc lib network oml4py oraInst.loc perl QOpatch relnotes sdk sqlpatch ucp
[root@ ~]# /opt/oracle/product/23c/dbhomeFree/root.sh
Check /opt/oracle/product/23c/dbhomeFree/install/root_************_2023-12-20_11-38-30-060078626.log for the output of root script

— Comme indiqué en fin d’installation, lancer ‘/etc/init.d/oracle-free-23c configure’ sous “root” pour créer une nouvelle instance. Le script est interactif et vous serez amener à saisir certaines informations comme le mot de passe SYS/SYSTEM et PDB_ADMIN.

[root@~]# /etc/init.d/oracle-free-23c configure
Specify a password to be used for database accounts. Oracle recommends that the password entered should be at least 8 characters in length, contain at least 1 uppercase character, 1 lower case character and 1 digit [0-9]. Note that the same password will be used for SYS, SYSTEM and PDBADMIN accounts:
Confirm the password:
Configuring Oracle Listener.
Listener configuration succeeded.
Configuring Oracle Database FREE.
Enter SYS user password:
************
Enter SYSTEM user password:
**************
Enter PDBADMIN User Password:
************
Prepare for db operation
7% complete
Copying database files
29% complete
Creating and starting Oracle instance
30% complete
33% complete
36% complete
39% complete
[WARNING] ORA-20002: Directory creation failed
ORA-06512: at "SYS.DBMS_QOPATCH", line 1644
ORA-06512: at "SYS.DBMS_QOPATCH", line 1521
ORA-06512: at line 1

43% complete
Completing Database Creation
47% complete
49% complete
50% complete
Creating Pluggable Databases
54% complete
71% complete
Executing Post Configuration Actions
93% complete
Running Custom Scripts
100% complete
Database creation complete. For details check the logfiles at:
/opt/oracle/cfgtoollogs/dbca/FREE.
Database Information:
Global Database Name:FREE
System Identifier(SID):FREE
Look at the log file "/opt/oracle/cfgtoollogs/dbca/FREE/FREE1.log" for further details.

Database configuration failed. Check logs under '/opt/oracle/cfgtoollogs/dbca'.

 

Ne pas tenir compte de l’erreur lors de la création du DIRECTORY Oracle, celui ci pointe vers un répertoire inexistant sur la machine. Il nous sera possible d’en créer un ultérieurement.

 

Présentation SQL Firewall

Comme son nom l’indique , Oracle 23c SQL Firewall est un firewall applicatif qui, au delà d’un firewall web classique (WAF), est capable d’interpréter le code SQL en entrée directement en base.
Comme le montre l’image extraite de la documentation Oracle officielle, le processus passe par une phase d’apprentissage des différentes requêtes envoyées à la base de données.

 

Une liste des requêtes dites “autorisées” doit être générée afin de valider les opérations business officielles d’une production classique au cour de la journée.
Ceci peut bien évidemment être facilité par un éditeur qui connait parfaitement son application, et donc son modèle conceptuel de données et les requêtes SQL qui en découlent.

Une fois cette phase d’apprentissage établie, nous allons pouvoir valider les requêtes capturées  et dresser la liste “verte” des requêtes autorisées.

C’est à partir de la que l’on pourra potentiellement, empêcher tout autre code SQL de passer en base.
Le filtrage peut se faire selon plusieurs contextes à savoir, un utilisateur en particulier, une adresse IP où bien un programme.

 

Les prérequis pour Oracle 23c SQL Firewall

 

Rappelons que depuis la version 21c, Oracle nous impose la gestion du multitenant avec la possibilité de créer 3 PDBs gratuitement.
L’instance FREE comporte donc bien une PDB exploitable en lecture/écriture

 

[oracle@ ~]$ . oraenv
ORACLE_SID = [oracle] ? FREE
The Oracle base has been set to /opt/oracle
[oracle@ ~]$ sqlplus / as sysdba

SQL*Plus: Release 23.0.0.0.0 - Production on Wed Dec 20 11:46:08 2023
Version 23.3.0.23.09

Copyright (c) 1982, 2023, Oracle. All rights reserved.

Connected to:
Oracle Database 23c Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free
Version 23.3.0.23.09

SQL> show pdbs;

CON_ID     CON_NAME                       OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
2          PDB$SEED                       READ ONLY  NO
3          FREEPDB1                       READ WRITE NO

 

Il sera donc nécessaire, pour se connecter à la PDB FREEPPDB1 depuis un compte applicatif, d’ajouter une entrée dans le tnsnames.

 

FREEPDB1 =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = ip-********.eu-west-3.compute.internal)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = FREEPDB1)
)
)

Configuration des données.

Pour notre cas pratique, nous créons 3 utilisateurs Oracle dans la PDB. 1 utilisateur administrateur du Firewall, 1 utilisateur propriétaire des objets et 1 utilisateur applicatif utilisant des ordres DML sur les objets. A noter le rôle “sql_firewall_admin” pour le compte “FW_ADMIN”.

 

SQL> alter session set container = FREEPDB1;

SQL> create user FW_ADMIN identified by passwdfwadmin;
SQL> grant create session, sql_firewall_admin, audit_admin to FW_ADMIN;
SQL> create user application_owner identified by passwdappliowner default tablespace USERS quota unlimited on USERS;
SQL> grant create session, create table, create view, create procedure, create synonym to application_owner;
SQL> create user application identified by passwdappli default tablespace USERS quota unlimited on USERS;
SQL> grant create session to application;
SQL> grant select any table on schema application_owner to application;

 

Création des objets et du jeu de données


SQL>  create table salaries ( id number(15), name VARCHAR2(128), address VARCHAR2(400), date_entrée VARCHAR2(128));
SQL>  create table entreprise (ent_id VARCHAR2(128), raison_sociale varchar2(20),taille_salaries number(5));

SQL>  insert into salaries values (154484, 'Manuel', '14 rue voltaire', '16/12/2020');
SQL>  insert into salaries values (275558, 'Jack', '24 rue du départ', '12/10/2005');
SQL>  insert into salaries values (285548, 'Cyril', '27 avenue Pasteur', '01/02/2006');
SQL>  insert into salaries values (472245, 'Thomas', '12 avenue principale', '15/02/2021');

SQL>  insert into entreprise values (12232,'SARL',1200);
SQL>  insert into entreprise values (13456,'SARL', 500);
SQL>  insert into entreprise values (22522,'SA',288);
SQL>  insert into entreprise values (25485,'SA', 144);
SQL>  insert into entreprise values (31411,'SA',524);
SQL>  insert into entreprise values (36879,'SARL', 56);
SQL>  insert into entreprise values (40125,'EURL', 120);
SQL>  insert into entreprise values (44588, 'SA', 2510);

SQL>  create or replace view application_owner.somme_salaries_sa
as
select raison_sociale, sum(taille_salaries) as "Somme_SA"
from application_owner.entreprise
where raison_sociale='SA'
group by raison_sociale;

SQL>  create or replace procedure maj_salarie_addresse (id number, address varchar2)
is
req varchar2(1000);
begin
req := 'BEGIN UPDATE salaries SET address = ''' || address || ''' WHERE id = ''' || id || '''; COMMIT; END;';
DBMS_OUTPUT.PUT_LINE('Query: ' || req);
execute immediate req;
end;
/

SQL>  CREATE OR REPLACE PROCEDURE maj_entreprise_salaries ( id number, taille_salaries number)
IS
req VARCHAR2(1000);
BEGIN

req := 'BEGIN UPDATE entreprise SET taille_salaries =''' || taille_salaries || ''' WHERE ent_id = ''' || id || '''; COMMIT; END;';
DBMS_OUTPUT.PUT_LINE('Query: ' || req);
EXECUTE IMMEDIATE req;
END;
/

SQL>  grant execute on application_owner.maj_salarie_addresse to application;
SQL>  grant execute on application_owner.maj_entreprise_salaries to application;
SQL>  grant select on application_owner.somme_salaries_sa to application;
SQL>  grant insert, update, delete on application_owner.salaries to application;
SQL>  grant insert, update, delete on application_owner.entreprise to application;
SQL>  create public synonym somme_salaries_sa for application_owner.somme_salaries_sa;
SQL>  create public synonym maj_salarie_addresse for application_owner.maj_salarie_addresse;
SQL>  create public synonym maj_entreprise_salaries for application_owner.maj_entreprise_salaries;

 

Capture des requêtes dans Oracle 23c SQL Firewall

 

A cette étape, nous pouvons commencer à capturer de l’activité afin de débuter “l’apprentissage” pour le SQL Firewall.

Tout d’abord, il nous faut activer le Firewall et vérifier son statut avec le compte FW_ADMIN.

 

SQL> connect fw_admin@freepdb1
Enter password:
Connected.
SQL> exec dbms_sql_firewall.enable;

PL/SQL procedure successfully completed.

SQL>  select STATUS,STATUS_UPDATED_ON from dba_sql_firewall_status;

STATUS   STATUS_UPDATED_ON
-------- ---------------------------------------------------------------------------
ENABLED  20-DEC-23 03.45.23.677823 PM +00:00

 

Démarrer la capture d’activité pour l’utilisateur Oracle nommé application.

SQL>  exec dbms_sql_firewall.create_capture('APPLICATION'); 

Vérifier le statut de la capture

SQL> col LAST_STARTED_ON for a35
SQL> col LAST_STOPPED_ON for a35
SQL> select * from dba_sql_firewall_captures where username='APPLICATION';

USERNAME        TOP_LEVEL_ONLY STATUS   LAST_STARTED_ON                     LAST_STOPPED_ON
--------------- -------------- -------- ----------------------------------- -----------------------------------
APPLICATION     N              ENABLED  20-DEC-23 03.49.48.573900 PM +00:00                                     

 

La suite consiste donc à générer de l’activité avec le compte APPLICATION

 

SQL> conn application@FREEPDB1
Connected.
SQL> execute maj_salarie_addresse(154484, '18 rue voltaire');

SQL> execute maj_entreprise_salaries(25485, 146);

SQL> select name, address from application_owner.salaries where id = 472245;

SQL> insert into application_owner.salaries values (510024, 'Marie', '12 rue de l eglise', '20/12/2023');

SQL> select name, address from application_owner.salaries where id = 510024;

SQL> delete from application_owner.salaries where id = 510024;

SQL> select name, address application_owner.salaries where id = 510024;

SQL> select * from application_owner.somme_salaries_sa;

SQL> select count(*) from application_owner.salaries where date_entrée > '01/01/2015';

 

Allons voir à présent ce que le Firewall a capturé comme requêtes. Stoppons la capture et allons lire dans les logs du Firewall

 

SQL> exec dbms_sql_firewall.stop_capture('APPLICATION');

PL/SQL procedure successfully completed.

SQL> select username, ip_address, login_time, client_program, os_user from dba_sql_firewall_session_logs order by login_time;

USERNAME        IP_ADDRESS      LOGIN_TIME                          CLIENT_PROGRAM                                     OS_USER
--------------- --------------- ----------------------------------- -------------------------------------------------- --------------------
APPLICATION     172.44.****     20-DEC-23 04.08.38.884619 PM +00:00 sqlplus@ip-********.fr (TNS V1-V3)                 oracle
APPLICATION     172.44.****     20-DEC-23 04.15.26.633200 PM +00:00 sqlplus@ip-********.fr (TNS V1-V3)                 oracle
APPLICATION     172.44.****     20-DEC-23 04.19.46.220001 PM +00:00 sqlplus@ip-********.fr (TNS V1-V3)                 oracle

 

Nous avons capturé les différentes connexions avec le compte APPLICATION, grâce à cela, les informations sur les SQL lancés sont enregistrées.
A noter que les variables enregistrées sont “bindés”

 

SQL> select username, top_level, command_type, sql_text,sql_signature,accessed_objects from dba_sql_firewall_capture_logs where username = 'APPLICATION' order by command_type, sql_signature;

USERNAME TOP_LEVEL COMMAND_TYPE
--------------- --------- ----------------------------------------------------------------
SQL_TEXT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_SIGNATURE
----------------------------------------------------------------
ACCESSED_OBJECTS
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
APPLICATION Y DELETE
DELETE FROM APPLICATION_OWNER.SALARIES WHERE ID=:"SYS_B_0"
0D3C48AFA7C43F32036A1398B2C9FED8250C57D00C9731332E8B6BFAAD25F3A0
"APPLICATION_OWNER"."SALARIES"

APPLICATION N EXECUTE
BEGIN UPDATE ENTREPRISE SET TAILLE_SALARIES=? WHERE ENT_ID=?; COMMIT; END;
243A35B41DAB8171B60C30BE90A3D725DEEDA3A22C8E118B5EB7E99C8D73E890
"APPLICATION_OWNER"."ENTREPRISE"

APPLICATION Y EXECUTE
BEGIN MAJ_SALARIE_ADDRESSE (?,?); END;
6A8D28786FE3BFEBFEBEE70CF2AF81A3587F5FE8239696BE9939D443EFB52789
"APPLICATION_OWNER"."MAJ_SALARIE_ADDRESSE"

APPLICATION N EXECUTE
BEGIN UPDATE SALARIES SET ADDRESS=? WHERE ID=?; COMMIT; END;
ED3DA8C122700A399BEB2D6C0CC88E5FC1B46A61961BF515E5DB0526856AD86A
"APPLICATION_OWNER"."SALARIES"

APPLICATION Y EXECUTE
BEGIN MAJ_ENTREPRISE_SALARIES (?,?); END;
F4F779482E86BC0537A6BC59470DB7E8A0EBBCF3B6F2CB21CE3242DC2863C45A
"APPLICATION_OWNER"."MAJ_ENTREPRISE_SALARIES"

APPLICATION Y INSERT
INSERT INTO APPLICATION_OWNER.SALARIES VALUES (:"SYS_B_0",:"SYS_B_1",:"SYS_B_2",:"SYS_B_3")
C24B251483E84751353F7B379414FFFBEBCC593E3E1CC32C0E419B69A66CA807
"APPLICATION_OWNER"."SALARIES"

APPLICATION Y SELECT
SELECT NAME,ADDRESS FROM APPLICATION_OWNER.SALARIES WHERE ID=:"SYS_B_0"
633C0FBB9B54CB5F6BC0A75B9BA34A2EA453671A78A799644CF4D7956F6EEE4B
"APPLICATION_OWNER"."SALARIES"

APPLICATION Y SELECT
SELECT NAME,ADDRESS FROM APPLICATION_OWNER.SALARIES WHERE ID=:"SYS_B_0"
633C0FBB9B54CB5F6BC0A75B9BA34A2EA453671A78A799644CF4D7956F6EEE4B
"APPLICATION_OWNER"."SALARIES"

APPLICATION Y SELECT
SELECT DECODE (USER,:"SYS_B_0",XS_SYS_CONTEXT (:"SYS_B_1",:"SYS_B_2"),USER) FROM SYS.DUAL
8CD0E5550A8AF32553BDED7C77B8CC1FD103C51F438E11F1BC5F9CA315102794
"SYS"."DUAL"

APPLICATION Y SELECT
SELECT DECODE (USER,:"SYS_B_0",XS_SYS_CONTEXT (:"SYS_B_1",:"SYS_B_2"),USER) FROM SYS.DUAL
8CD0E5550A8AF32553BDED7C77B8CC1FD103C51F438E11F1BC5F9CA315102794
"SYS"."DUAL"

APPLICATION Y SELECT
SELECT DECODE (USER,:"SYS_B_0",XS_SYS_CONTEXT (:"SYS_B_1",:"SYS_B_2"),USER) FROM SYS.DUAL
8CD0E5550A8AF32553BDED7C77B8CC1FD103C51F438E11F1BC5F9CA315102794
"SYS"."DUAL"

APPLICATION Y SELECT
SELECT * FROM APPLICATION_OWNER.SOMME_SALARIES_SA
BCCB5D0F6B4DE96D7C9E52C8678C489698D4ED23F8FEEA120FFC701560C99D0C
"APPLICATION_OWNER"."SOMME_SALARIES_SA"

APPLICATION Y SELECT
SELECT * FROM APPLICATION_OWNER.SOMME_SALARIES_SA
BCCB5D0F6B4DE96D7C9E52C8678C489698D4ED23F8FEEA120FFC701560C99D0C
"APPLICATION_OWNER"."SOMME_SALARIES_SA"

APPLICATION Y SELECT
SELECT COUNT (*) FROM APPLICATION_OWNER.SALARIES WHERE DATE_ENTR??E >:"SYS_B_0"
EE000C28DC61F8D21DCDC9BB6880A315EB12CC3682E0D3CD47A01EACF915EF98
"APPLICATION_OWNER"."SALARIES"

APPLICATION Y SELECT
SELECT COUNT (*) FROM APPLICATION_OWNER.SALARIES WHERE DATE_ENTR??E >:"SYS_B_0"
EE000C28DC61F8D21DCDC9BB6880A315EB12CC3682E0D3CD47A01EACF915EF98
"APPLICATION_OWNER"."SALARIES"

APPLICATION N UPDATE
UPDATE ENTREPRISE SET TAILLE_SALARIES=:"SYS_B_0" WHERE ENT_ID=:"SYS_B_1"
36FE5B2C529FD88D46DD6C69649D30C12719CD2600945F8EF2D4B3D039B4CD06
"APPLICATION_OWNER"."ENTREPRISE"

APPLICATION N UPDATE
UPDATE SALARIES SET ADDRESS=:"SYS_B_0" WHERE ID=:"SYS_B_1"
6D68C8BB02FFE46E37900E60275B0AB0698CF1217B95B3CA1C789E29FE8D0B6B
"APPLICATION_OWNER"."SALARIES"

 

Chaque ordre SQL a une signature propre à lui. C’est ce qui permet au SQL Firewall de reconnaitre par la suite, tout ordre faisant parti de la liste.

 

Générer la liste “verte” de requêtes autorisées

La liste “verte” se crée avec le compte FW_ADMIN

 

SQL> connect fw_admin@FREEPDB1
Enter password:
Connected.
SQL> exec dbms_sql_firewall.generate_allow_list('APPLICATION');

PL/SQL procedure successfully completed.

SQL>; col GENERATED_ON for a35
SQL> select USERNAME,GENERATED_ON,STATUS,STATUS_UPDATED_ON,TOP_LEVEL_ONLY from dba_sql_firewall_allow_lists where username='APPLICATION';

USERNAME              GENERATED_ON                        STATUS   STATUS_UPDATED_ON                   TOP_LEVEL_ONLY
---------------       ----------------------------------- -------- ----------------------------------- --------------
APPLICATION           20-DEC-23 04.49.56.169700 PM +00:00 DISABLED 20-DEC-23 04.49.56.169700 PM +00:00 N

 

Pour le moment, le statut de la liste est à DISABLED car nous l’avons juste générée.

Comme évoqué quelques lignes au dessus, le contexte peut se faire via l’adresse IP

 

SQL> select * from sys.dba_sql_firewall_allowed_ip_addr where username='APPLICATION';

USERNAME             IP_ADDRESS
-------------------- ------------------------------
APPLICATION          172.44.*********

 

Le programme associé

 

SQL> select * from sys.dba_sql_firewall_allowed_os_prog where username='APPLICATION';

USERNAME               OS_PROGRAM
--------------------   --------------------------------------------------------------------------------------------------------------------------------
APPLICATION            sqlplus@ip-172-44-*************s.fr (TNS V1-V3)

 

Ou bien le user OS

 

SQL> select * from sys.dba_sql_firewall_allowed_os_user where username='APPLICATION';

USERNAME               OS_USER
--------------------   --------------------------------------------------------------------------------------------------------------------------------
APPLICATION            oracle

 

Activer la liste “verte”

 

la suite consiste à valider et surtout, activer cette liste. Ceci se fait avec le compte FW_ADMIN.

 

SQL> connect fw_admin@FREEPDB1
Enter password:
Connected.
SQL> exec dbms_sql_firewall.enable_allow_list('APPLICATION');

PL/SQL procedure successfully completed.

SQL> select username, status, top_level_only, enforce, block from dba_sql_firewall_allow_lists where username='APPLICATION';

USERNAME             STATUS          TOP_LEVEL_ONLY ENFORCE         BLOCK
-------------------- --------------  -------------- --------------- --------------
APPLICATION          ENABLED         N              ENFORCE_ALL     N

 

 

 

Cette liste “verte” est donc activée, elle “trappe” les futures requêtes qui ne matcheraient pas avec celles qui sont enregistrées. Mais, le “BLOCK” est à N, donc l’utilisateur n’a pas de message d’erreur en cas de saisie d’une requête non reconnue.

Le user APPLICATION peut tout à fait faire un SELECT sur une table.

 

SQL> connect application@FREEPDB1
Enter password:
Connected.
SQL> select name from application_owner.salaries where id > 300000;

NAME
--------------------------------------------------------------------------------------------------------------------------------
Manuel
Jack
Cyril

 

Mais une fois connecté avec le user FW_ADMIN, une simple interrogation dans la vue DBA_SQL_FIREWALL_VIOLATIONS nous donne l’entrée suivante

SQL> select USERNAME,COMMAND_TYPE,SQL_TEXT,IP_ADDRESS,OS_USER,OCCURRED_AT from dba_sql_firewall_violations;

USERNAME             COMMAND_TYPE                  SQL_TEXT                                                                              IP_ADDRESS          OS_USER</pre>
-------------------- ---------------               --------------------------------------------------------------------------------      ---------------     ---------------
OCCURRED_AT
---------------------------------------------------------------------------
APPLICATION          SELECT                        SELECT NAME FROM APPLICATION_OWNER.SALARIES WHERE ID <:"SYS_B_0"                      172.44.******        oracle
21-DEC-23 02.09.53.047973 PM +00:00

 

La requête lancée par le compte APPLICATION est donc bien enregistrée dans la liste des violations des règles du firewall.

 

Bloquer les requêtes non désirées

Le blocage de requêtes s’effecctue, avec le compte FW_ADMIN, en activant le mode BLOCK sur la liste “verte”

 

SQL> connect fw_admin@FREEPDB1
Enter password:
Connected.
SQL> exec dbms_sql_firewall.update_allow_list_enforcement('APPLICATION', block=>TRUE);

PL/SQL procedure successfully completed.

 

Et lorsque nous souhaitons interroger la même requête avec le compte APPLICATION

 

SQL> connect application@FREEPDB1
Enter password:
Connected.
SQL> select name from application_owner.salaries where id > 300000;
select name from application_owner.salaries where id > 300000
*
ERROR at line 1:
ORA-47605: SQL Firewall violation
Help: https://docs.oracle.com/error-help/db/ora-47605/

 

Nous avons une belle erreur “ORA-47605” nous indiquant une violation des règles du Firewall. Petite nouveauté avec la 23c, Oracle nous donne l’URL pour rechercher directement la définition du message d’erreur.

Ceci se vérifie pour toute autre requête ne faisant pas partie de la liste “verte”

 

SQL> select * from application_owner.entreprise where taille_salaries > 10000;
select * from application_owner.entreprise where taille_salaries > 10000
*
ERROR at line 1:
ORA-47605: SQL Firewall violation
Help: https://docs.oracle.com/error-help/db/ora-47605/

 

Dans la vue DBA_SQL_FIREWALL_VIOLATIONS, ces 2 dernières requêtes nous sont relevées

SQL> connect fw_admin@FREEPDB1
Enter password:
Connected.
SQL> select USERNAME,COMMAND_TYPE,SQL_TEXT,OCCURRED_AT from dba_sql_firewall_violations;

USERNAME COMMAND_TYPE SQL_TEXT
-------------------- --------------- --------------------------------------------------------------------------------
OCCURRED_AT
---------------------------------------------------------------------------
APPLICATION SELECT SELECT * FROM APPLICATION_OWNER.ENTREPRISE WHERE TAILLE_SALARIES >:"SYS_B_0"
21-DEC-23 02.30.31.690170 PM +00:00

APPLICATION SELECT SELECT NAME FROM APPLICATION_OWNER.SALARIES WHERE ID <:"SYS_B_0"
21-DEC-23 02.09.53.047973 PM +00:00

APPLICATION SELECT SELECT NAME FROM APPLICATION_OWNER.SALARIES WHERE ID <:"SYS_B_0"
21-DEC-23 02.24.29.523017 PM +00:00

 

Il est bien entendu possible de purger la table de log des requêtes interdites afin de réinitialiser son contenu.

 

SQL> exec dbms_sql_firewall.purge_log('APPLICATION', NULL, dbms_sql_firewall.VIOLATION_LOG);

PL/SQL procedure successfully completed.

SQL> select USERNAME,COMMAND_TYPE,SQL_TEXT,OCCURRED_AT from dba_sql_firewall_violations;

no rows selected

 

Conclusion

 

Gardez à l’esprit que cette fonctionnalité SQL Firewall de Oracle peut vous protéger de toute injection SQL non désirée, mais ceci sous entend surtout que la phase “d’apprentissage” soit correctement maitrisée afin de ne pas se retrouver avec une application potentiellement bloquée par des ordres SQL qui ne s’exécutent plus.

C’est bien pour cela que cette phase peut être longue, et nécessite le recensement de très nombreuses requêtes trappées dans DBA_SQL_FIREWALL_ALLOWED_SQL.
La valeur de “SQL_SIGNATURE” est essentielle , dans la mesure ou le relevé des variables est “bindé”, les requêtes suivantes seront autorisées même si les résultats sont différents  :

SQL> select name, address from application_owner.salaries where id = 510024;

SQL> select name, address from application_owner.salaries where id = 285548;

 

Pensez également à purger la vue DBA_SQL_FIREWALL_VIOLATIONS de façon régulière, tout en portant attention sur ce qui aura été relevé durant les périodes de production.

 

🙂

Continuez votre lecture sur le blog :

twitterlinkedinmail

Emmanuel RAMI

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.