- Sabemos que existe vários casos onde o uso de bind variables pode nos ajudar bastante do ponto de vista da peformance das consultas, mas uma outra área que devemos ter cuidado ao usar binds, é a da segurança de nosso banco. Vou mostrar na prática como o uso de bind pode nos ajudar a dar mais segurança ao código.
- Faço a criação da nossa tabela de testes e depois faço insert de algumas linhas.
create table clientes (pri_nome varchar2(50), ult_nome varchar2(50));
insert into clientes values ('Thiago','Castro');
insert into clientes values ('Lucas','Costa');
insert into clientes values ('João','Souza');
insert into clientes values ('Antônio','Pereira');
commit;
1 row created.
SQL>
1 row created.
SQL>
1 row created.
SQL>
1 row created.
SQL>
Commit complete.
- Vamos criar uma procedure bem simples, a teste_inject. Como podemos ver no código, ela pega o parâmetro passado, o ultimo nome do cliente, e faz uma contagem na tabela de clientes para saber a quantidade de clientes que tenho com o sobre nome passado.
CREATE OR REPLACE PROCEDURE teste_inject_s_bind (nome in clientes.ult_nome%TYPE) IS
BEGIN
DECLARE
texto VARCHAR2(2000);
contagem NUMBER;
BEGIN
texto := 'SELECT COUNT(*) FROM clientes s WHERE s.ult_nome= '''||nome||'''';
EXECUTE IMMEDIATE texto INTO contagem;
DBMS_OUTPUT.PUT_LINE ('Quantidade de clientes: '||TO_CHAR(contagem));
END;
END teste_inject_s_bind;
/
Procedure created.
- Executei a procedure de duas formas. Na primeira forma, com o comportamento normal do programa e na segunda passei um parâmetro diferente que alterou o comportamento do código. Sei que nesse exemplo isso não quer dizer muita coisa, mas imaginem se nessa tabela estivessem dados sigilosos.
Abaixo o comportamento da procedure com os dois parâmetros:
Execução 1
SQL> exec teste_inject_s_bind('Castro');
Quantidade de clientes: 1
PL/SQL procedure successfully completed.
Execução 2
SQL> exec teste_inject_s_bind(''' or 1=1--');
Quantidade de clientes: 4
PL/SQL procedure successfully completed.
SQL> SELECT COUNT(*) FROM clientes s WHERE s.ult_nome='' or 1=1--';
COUNT(*)
----------
4
- Certo sabemos que o código tem uma falha, o que fazer para consertar o problema? Na procedure teste_inject_s_bind se tivéssemos usado binds, evitaríamos esse problema. Então vamos criar uma nova procedure, só que agora com uso de bind.
CREATE OR REPLACE procedure teste_inject_c_bind (nome in clientes.ult_nome%TYPE) IS
BEGIN
DECLARE
texto VARCHAR2(2000);
contagem NUMBER;
BEGIN
texto := 'SELECT COUNT(*) FROM clientes s WHERE s.ult_nome= :p_nome';
EXECUTE IMMEDIATE texto INTO contagem USING nome;
DBMS_OUTPUT.PUT_LINE ('Quantidade de clientes: '||TO_CHAR(contagem));
END;
END teste_inject_c_bind;
/
Procedure created.
- Agora vamos executar a nova procedure com os mesmos parâmetros.
1 Execução
SQL> exec teste_inject_c_bind('Castro');
Quantidade de clientes: 1
PL/SQL procedure successfully completed.
2 Execução
SQL> exec teste_inject_c_bind(''' or 1=1--');
Quantidade de clientes: 0
PL/SQL procedure successfully completed.
- Repare que na segunda execução da teste_inject_c_bind, o retorno foi 0, ou seja, o nosso parâmetro para alterar o resultado da consulta não funcionou.
Comentários