在与 DBA 讨论安全性之后,我正在开发使用动态查询根据用户输入执行选择语句的应用程序,他们希望我将动态选择语句转换为存储过程。
我已经使用 MSSQL 构建了动态 sql,但我不知道如何将其转换为 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
*请注意,我想防止 SQL 注入我不想只是将字符串添加在一起
**我已经建立了一个单独的类,用于在 .net 中为我的应用程序创建这个动态查询我有近 1000 行代码来处理所有事情并防止 sql 注入,但 DBA 告诉我他们想要存储过程,以便他们可以控制输入和输出。
这可能会给你一个想法:
稍后,在 SQL*Plus 中:
编辑:评论是对的,程序受SQL注入。因此,为了防止这种情况,您可以使用绑定变量,例如在这个修改过的过程中:
请注意,现在,无论输入如何,select 语句都变得类似
select ... from ... where 1=1 and col1 like :1 and col2 :2 ...
,显然更安全。您不一定需要动态 SQL,因为某些 where 条件在不存在时不适用。
将此代码放在包内的存储过程中是一个绝妙的主意。
Oracle 提供了一些优秀的文档,可以帮助您快速了解存储过程和包。您可能希望从概念指南开始了解 Oracle 的工作原理,然后转到SQL 语言参考和PL/SQL 语言参考以获取与当前任务相关的信息。
这不是独立的答案,而是对 René Nyffenegger 使用绑定变量的代码的附加解释。
SaUce 询问为什么这段代码对 sql 注入免疫。
在这里,我将 René 的代码更改为不执行动态语句,而是显示它:
现在我可以尝试像这样的电话
结果是:
在 René 的代码中,这将被执行为:
您会看到,为 FirstN 提供哪个值并不重要。它永远不会改变查询的含义。
使用变量绑定还有其他原因,这对于具有 SQL-Server 背景的开发人员来说很难掌握。它们取决于 Oracle 在共享池中存储预编译执行计划的方式。不使用绑定变量会给出不同的语句和不同的执行计划,而使用绑定变量会使用单个执行计划。
对于您的存储过程,最好的迁移到 oracle 就像
好吧,晚了,我有点懒,但填写剩下的 12 个案例是直截了当的。
不使用动态 SQL 有一些优点:
不要因为它对人类来说看起来很无聊,就认为它对计算机不利(尤其是在运行 Oracle 时)。
但是不要为了强迫我展示使用动态 sql 的解决方案而添加更多参数,而是要避免需要此类解决方案的疯狂设计。