Estou trabalhando em um aplicativo que usa consulta dinâmica para fazer uma instrução select com base na entrada do usuário, depois de discutir segurança com DBAs eles querem que eu converta minha instrução de seleção dinâmica em procedimento armazenado.
Eu construí sql dinâmico usando MSSQL, mas não consigo descobrir como convertê-lo para Oracle SQL.
CREATE PROCEDURE GetCustomer
@FirstN nvarchar(20) = NULL,
@LastN nvarchar(20) = NULL,
@CUserName nvarchar(10) = NULL,
@CID nvarchar(15) = NULL as
DECLARE @sql nvarchar(4000),
SELECT @sql = 'C_FirstName, C_LastName, C_UserName, C_UserID ' +
'FROM CUSTOMER ' +
'WHERE 1=1 ' +
IF @FirstN IS NOT NULL
SELECT @sql = @sql + ' AND C_FirstName like @FirstN '
IF @LastN IS NOT NULL
SELECT @sql = @sql + ' AND C_LastName like @LastN '
IF @CUserName IS NOT NULL
SELECT @sql = @sql + ' AND C_UserName like @CUserName '
IF @CID IS NOT NULL
SELECT @sql = @sql + ' AND C_UserID like @CID '
EXEC sp_executesql @sql, N'@C_FirstName nvarchar(20), @C_LastName nvarchar(20), @CUserName nvarchar(10), @CID nvarchar(15)',
@FirstN, @LastN, @CUserName, @CID
*por favor, note que eu quero evitar a injeção de SQL, não quero apenas adicionar strings
**criei uma classe separada para criar essa consulta dinâmica para meu aplicativo em .net, tenho quase 1000 linhas de código para lidar com tudo e evitar injeção de sql, mas os DBAs me disseram que querem procedimentos armazenados para que possam controlar entrada e resultado.
Isso pode te dar uma ideia:
Mais tarde, no SQL*Plus:
Edit : O comentário está correto e o procedimento está sujeito a injeção de SQL . Portanto, para evitar isso, você pode usar variáveis de ligação, como neste procedimento modificado:
Observe que agora, qualquer que seja a entrada, a instrução select se torna algo
select ... from ... where 1=1 and col1 like :1 and col2 :2 ...
que obviamente é muito mais seguro.Você não precisa necessariamente de SQL dinâmico apenas porque certas condições não se aplicam quando não estão presentes.
Colocar esse código em um procedimento armazenado dentro de um pacote é uma excelente ideia.
A Oracle fornece uma excelente documentação que pode agilizar os procedimentos e pacotes armazenados. Você pode querer começar com o Guia de Conceitos para entender como o Oracle funciona e, em seguida, passar para a Referência da Linguagem SQL e a Referência da Linguagem PL/SQL para obter informações pertinentes à sua tarefa atual.
Esta não é uma resposta independente, mas uma explicação adicional ao código de René Nyffenegger usando variáveis de ligação.
SaUce perguntou por que esse código é imune à injeção de SQL.
Aqui eu mudo o código do René para não executar a instrução dinâmica, mas para exibi-la:
Agora posso tentar chamadas como
O resultado é:
No código de René isso será executado como:
Veja bem, não importa qual valor é fornecido para FirstN. Ele nunca muda o significado da consulta.
Existem outras razões para usar a vinculação de variáveis, que são difíceis de entender para desenvolvedores com experiência em SQL-Server. Eles dependem da maneira como o Oracle armazena planos de execução pré-compilados no pool compartilhado. Não usar variáveis de ligação fornece instruções diferentes e planos de execução diferentes, enquanto usar variáveis de ligação usa um único plano de execução.
Para seu procedimento armazenado, a melhor migração para o oracle seria
OK, é tarde e estou um pouco preguiçoso, mas preencher os 12 casos restantes é simples.
Não usar SQL dinâmico tem algumas vantagens:
Não pense porque parece chato para um humano, que é ruim para um computador (especialmente ao executar o Oracle).
Mas não adicione mais parâmetros apenas para me forçar a mostrar uma solução usando sql dinâmico, em vez disso, evite projetos insanos que exijam tais soluções.