Neste post, vou apresentar o que é o SQL Firewall, como configurá-lo e alguns exemplos práticos que mostram como ele funciona na proteção contra SQL injection e comandos não autorizados.
O que é o SQL Firewall?
O SQL Firewall é um recurso de segurança de banco de dados incorporado ao kernel do Oracle Database 23ai, que inspeciona as conexões e instruções SQL recebidas, permitindo, registrando ou bloqueando atividades não autorizadas conforme as políticas específicas de cada usuário do banco de dados.
O SQL Firewall garante que apenas instruções SQL explicitamente autorizadas sejam executadas, bloqueando tentativas de injeção de SQL.
Ele está disponível apenas para versões Enterprise Edition a partir da 23ai com a option database vault e nas versões cloud abaixo?
- Oracle Base Database Service Enterprise Edition - High Performance (BaseDB EE-HP)
- Oracle Base Database Service Enterprise Edition - Extreme Performance (BaseDB EE-EP)
- Oracle Exadata Database Service on Dedicated Infrastructure (ExaDB)
- Oracle Exadata Database Service on Cloud@Customer (ExaDB)
Como funciona?
O SQL Firewall funciona aprendendo o tráfego SQL normal de um usuário do banco de dados, incluindo quais instruções SQL são esperadas desse usuário e o contexto em que ele se conecta ao banco de dados, como o endereço de rede, o usuário do sistema operacional e o programa utilizado. Uma vez treinado, o SQL Firewall pode:
-
Registrar e bloquear desvios do comportamento normal
-
Identificar instruções SQL incomuns
-
Identificar conexões provenientes de endereços ou programas que não estão na lista de permissões
Configurando o SQL Firewall
1 - Habilitando o SQL Firewall para um usuário
SQL> select status from dba_sql_firewall_status;
STATUS
--------
DISABLED
SQL> exec dbms_sql_firewall.enable;
PL/SQL procedure successfully completed.
SQL> select status from dba_sql_firewall_status;
STATUS
--------
ENABLED
SQL>
SQL> select status from dba_sql_firewall_status;
STATUS -------- DISABLED SQL> exec dbms_sql_firewall.enable; PL/SQL procedure successfully completed. SQL> select status from dba_sql_firewall_status; STATUS -------- ENABLED SQL>
2 - Iniciando o modo de captura
SQL> begin dbms_sql_firewall.create_capture ( username => 'LAMIM', top_level_only => true, start_capture => true); end; / SQL> 2 3 4 5 6 7 PL/SQL procedure successfully completed. SQL>
A partir deste momento as consultas realizadas pelo usuário serão capturadas. Para simular o processo, criei 2 tabelas, inseri alguns dados fictícios e depois realizei um select nas mesmas.
SQL> SQL> create table LAMIM.TABELA01(id number); Table created. SQL> insert into LAMIM.TABELA01 values (1); 1 row created. SQL> insert into LAMIM.TABELA01 values (2); 1 row created. SQL> create table LAMIM.TABELA02(data date); Table created. SQL> insert into LAMIM.TABELA02 values (sysdate); 1 row created. insert into LAMIM.TABELA02 values (sysdate +1); 1 row created. SQL> commit; SQL> show user; USER is "LAMIM" SQL> select * from tabela01; ID ---------- 1 2 SQL> select * from tabela02; DATA --------- 13-APR-25 14-APR-25 SQL>
Na view dba_sql_firewall_capture_logs é possível verificar os dados que foram coletados durante o modo captura.
SQL> SQL> set linesize 210 pagesize 40 SQL> column command_type format a12 SQL> column current_user format a15 column client_program format a45 column os_user format a10 column ip_address format a10 SQL> SQL> SQL> SQL> column sql_text format a90 select command_type, current_user, client_program, SQL> SQL> 2 3 4 os_user, ip_address, sql_text 5 6 7 from dba_sql_firewall_capture_logs where username = 'LAMIM'; 8 COMMAND_TYPE CURRENT_USER CLIENT_PROGRAM OS_USER IP_ADDRESS SQL_TEXT ------------ --------------- --------------------------------------------- ---------- ---------- ------------------------------------------------------------------------------------------ SELECT LAMIM sqlplus@dbsystem23ai (TNS V1-V3) oracle 10.0.0.32 SELECT * FROM TABELA01 SELECT LAMIM sqlplus@dbsystem23ai (TNS V1-V3) oracle 10.0.0.32 SELECT * FROM TABELA01 INSERT LAMIM sqlplus@dbsystem23ai (TNS V1-V3) oracle 10.0.0.32 INSERT INTO TABELA01 VALUES (:"SYS_B_0") INSERT LAMIM sqlplus@dbsystem23ai (TNS V1-V3) oracle 10.0.0.32 INSERT INTO TABELA02 VALUES (SYSDATE +:"SYS_B_0") SELECT LAMIM sqlplus@dbsystem23ai (TNS V1-V3) oracle 10.0.0.32 SELECT * FROM TABELA02 SELECT LAMIM sqlplus@dbsystem23ai (TNS V1-V3) oracle 10.0.0.32 SELECT * FROM TABELA02 SELECT LAMIM sqlplus@dbsystem23ai (TNS V1-V3) oracle 10.0.0.32 SELECT DECODE (USER,:"SYS_B_0",XS_SYS_CONTEXT (:"SYS_B_1",:"SYS_B_2"),USER) FROM SYS.DUAL SELECT LAMIM sqlplus@dbsystem23ai (TNS V1-V3) oracle 10.0.0.32 SELECT DECODE (USER,:"SYS_B_0",XS_SYS_CONTEXT (:"SYS_B_1",:"SYS_B_2"),USER) FROM SYS.DUAL 8 rows selected. SQL>
3 - parando o modo de captura
Supondo que a captura esteve ativa durante tempo suficiente para coletar o padrão de SQL do usuário, agora é o momento de parar a mesma.
SQL> SQL> exec dbms_sql_firewall.stop_capture('LAMIM'); PL/SQL procedure successfully completed. SQL>
Agora será gerada uma lista de permissões (allow-list) para o usuário com base nos logs de captura. O SQL Firewall cria a lista de permissões com base nos dados coletados dos registros de captura existentes para o usuário.
SQL> SQL> exec dbms_sql_firewall.generate_allow_list ('LAMIM'); PL/SQL procedure successfully completed. SQL>
Existem quatro views que nos permitem verificar o conteúdo da lista de permissões (allow-list). São elas a dba_sql_firewall_allowed_ip_addr, dba_sql_firewall_allowed_os_prog, dba_sql_firewall_allowed_os_user e dba_sql_firewall_allowed_sql
SQL> SQL> --Consultar o usuario e IP column username format a30 select * from dba_sql_firewall_allowed_ip_addr where username = 'LAMIM'; SQL> SQL> 2 3 USERNAME IP_ADDRESS ------------------------------ ---------- LAMIM 10.0.0.32 SQL> --Consultar o usuario e PROGRAMA column os_program format a60 select * from dba_sql_firewall_allowed_os_prog where username = 'LAMIM';SQL> SQL> 2 3 USERNAME OS_PROGRAM ------------------------------ ------------------------------------------------------------ LAMIM sqlplus@dbsystem23ai (TNS V1-V3) SQL> --Consultar o usuario e usuario de SO column os_user format a20 select * from dba_sql_firewall_allowed_os_user where username = 'LAMIM';SQL> SQL> 2 3 USERNAME OS_USER ------------------------------ -------------------- LAMIM oracle SQL> --Consultar o usuario e SQL column sql_text format a90 select current_user, sql_text from dba_sql_firewall_allowed_sql where username = 'LAMIM'; SQL> SQL> 2 3 4 CURRENT_USER SQL_TEXT --------------- ------------------------------------------------------------------------------------------ LAMIM CREATE TABLE TABELA03 AS SELECT * FROM TABELA02 LAMIM INSERT INTO TABELA02 VALUES (SYSDATE +:"SYS_B_0") LAMIM INSERT INTO TABELA01 VALUES (:"SYS_B_0") LAMIM SELECT * FROM TABELA01 LAMIM SELECT * FROM TABELA02 LAMIM SELECT DECODE (USER,:"SYS_B_0",XS_SYS_CONTEXT (:"SYS_B_1",:"SYS_B_2"),USER) FROM SYS.DUAL 6 rows selected. SQL> SQL>
3 - Ativando a Política de SQL Firewall para Proteção de Usuários
Nesta etapa é ativada a proteção do usuário. A partir do momento em que está ativa, o SQL Firewall passa a validar as listas de permissões sempre que o usuário se conecta e executa comandos SQL.
Essa ativação é imediata e se aplica inclusive às sessões que já estiverem em andamento para o usuário em questão.
Para iniciar a proteção é usada a procedure dbms_sql_firewall.enable_allow_list, passando além do usuário, o tipo de bloqueio (enforcement), sendo eles:
ENFORCE_CONTEXT: Aplica apenas a lista de permissões de contexto (endereço IP, usuário do sistema operacional e programa utilizado).
ENFORCE_SQL: Aplica apenas a lista de permissões de instruções SQL.
ENFORCE_ALL: Aplica tanto a lista de permissões de contexto quanto a de instruções SQL.
Neste exemplo, habilitamos tanto a lista de permissões de contexto quanto a de SQL. Definir o parâmetro BLOCK como true significa que as violações serão bloqueadas, já false significa que as violações serão registradas em log, mas não serão bloqueadas.
SQL> SQL> begin dbms_sql_firewall.enable_allow_list ( username => 'LAMIM', enforce => dbms_sql_firewall.enforce_all, block => false); end; / 2 3 4 5 6 7 PL/SQL procedure successfully completed. SQL>
Exemplo prático: tentativa de SQL Injection
Após o modo ENFORCE estar ativado, se um atacante tentar executar algum comando diferente, ou com um IP diferente, o Oracle irá bloquear automaticamente a execução desse comando, registrando o evento nas views de auditoria.
No exemplo acima a politica esta ativa com block => false, desta forma ele vai permitir a conexão gerar a lista de violações.
SQL> set lines 210 col ip_address for a20 col sql_text for a160 select sql_text, firewall_action, ip_address, cause from dba_sql_firewall_violations where username = 'LAMIM';SQL> SQL> SQL> 2 3 4 5 6 SQL_TEXT FIREWAL IP_ADDRESS CAUSE ---------------------------------------------------------------------------------------------------------------------------------------------------------------- ------- -------------------- ----------------- SELECT * FROM V$VERSION WHERE BANNER LIKE :"SYS_B_0" Allowed 179.127.190.77 SQL violation SELECT CON_ID FROM (SELECT SYS_CONTEXT (:"SYS_B_0",:"SYS_B_1") AS CON_ID FROM DUAL) WHERE CON_ID=:"SYS_B_2" Allowed 179.127.190.77 SQL violation SELECT INST_COUNT FROM (SELECT COUNT (*) INST_COUNT FROM GV$DATABASE) WHERE INST_COUNT >:"SYS_B_0" Allowed 179.127.190.77 SQL violation DECLARE L_SCHEMA VARCHAR2 (?); L_PART1 VARCHAR2 (?); L_PART2 VARCHAR2 (?); L_DBLINK VARCHAR2 (?); L_PART1_TYPE NUMBER; L_OBJID NUMBER; V_NAME VARCHAR2 (?); BEGI Allowed 179.127.190.77 SQL violation N V_NAME :=:OBJ_NAME; DBMS_UTILITY.NAME_RESOLVE (NAME => V_NAME,CONTEXT => ?,SCHEMA => L_SCHEMA,PART1 => L_PART1,PART2 => L_PART2,DBLINK => L_DBLINK,PART1_TYPE => L_PART1_TYPE,OBJECT_NUMBER => L_OBJID); EXCEPTION WHEN OTHERS THEN IF SQLCODE=-? THEN DBMS_UTILITY.NAME_RESOLVE (NAME => V_NAME,CONTEXT => ?,SCHEMA => L_SCHE MA,PART1 => L_PART1,PART2 => L_PART2,DBLINK => L_DBLINK,PART1_TYPE => L_PART1_TYPE,OBJECT_NUMBER => L_OBJID); ELSE RAISE; END IF; END; SELECT USER_ID FROM USER_USERS WHERE ALL_SHARD=:"SYS_B_0" Allowed 179.127.190.77 SQL violation
Alterando o block para true, através da procedure dbms_sql_firewall.update_allow_list_enforcement, as violações passam a ser bloqueadas.
SQL> SQL> SQL> begin dbms_sql_firewall.update_allow_list_enforcement( username => 'LAMIM', enforce => dbms_sql_firewall.enforce_all, block => true); end; / 2 3 4 5 6 7 PL/SQL procedure successfully completed. SQL> select username, status, top_level_only, enforce, block from dba_sql_firewall_allow_lists where username='LAMIM'; 2 3 4 5 6 7 USERNAME STATUS TOP_LEVEL_ONLY ENFORCE BLOCK ------------------------------ -------- -------------- --------------- -------------- LAMIM ENABLED Y ENFORCE_ALL Y SQL>
Ao tentar realizar um conexao, partindo de outro IP, recebo o erro abaixo no SQL Developer.
ORA-47605: Violação do SQL Firewall
Da mesma forma, se tentarmos realizar um comando SQL diferente dos que foram coletados durante o período ativo, teremos o mesmo erro.
SQL> SQL> select count(1) from tabela02; select count(1) from tabela02 * ERROR at line 1: ORA-47605: SQL Firewall violation Help: https://docs.oracle.com/error-help/db/ora-47605/ SQL>
Conclusão
https://www.oracle.com/a/ocom/docs/security/oracle-sql-firewall-faq.pdf
Comentários
Postar um comentário