37

我已经写了两个存储过程,一个有sp_executesql,另一个没有 sp_executesql

EXEC (@SQL) 与 EXEC sp_executesql @SQL, N'@eStatus varchar(12)', @eStatus = @Status

以及 EXEC(@SQL) 如何容易发生 SQL 注入,而 sp_executesql @SQL...... 不是吗?

下面没有 sp_executesql 的存储过程

ALTER proc USP_GetEmpByStatus
(
@Status varchar(12)
)
AS
BEGIN
DECLARE @TableName AS sysname = 'Employee'
Declare @Columns as sysname = '*'
DECLARE @SQL as nvarchar(128) = 'select ' + @Columns + ' from ' + @TableName + ' where Status=' + char(39) + @Status + char(39)
print (@SQL)
EXEC (@SQL)
END

EXEC USP_GetEmpByStatus 'Active'

下面带有 sp_executesql 的存储过程

create proc USP_GetEmpByStatusWithSpExcute
(
@Status varchar(12)
)
AS
BEGIN
DECLARE @TableName AS sysname = 'JProCo.dbo.Employee'
Declare @Columns as sysname = '*'
DECLARE @SQL as nvarchar(128) = 'select ' + @Columns + ' from ' + @TableName + ' where Status=' + char(39) + @Status + char(39)
print @SQL
exec sp_executesql @SQL, N'@eStatus varchar(12)', @eStatus = @Status
END

EXEC USP_GetEmpByStatusWithSpExcute 'Active'
4

3 回答 3

25

您的sp_executesql SQL 应该是;

DECLARE @SQL as nvarchar(128) = 'select ' + @Columns + ' from ' + 
            @TableName + ' where Status=@eStatus'

这将允许您使用 @eStatus 作为参数调用 sp_executesql,而不是将其嵌入到 SQL 中。这将带来@eStatus 可以包含任何字符的优势,并且如果需要安全,它将被数据库自动正确转义。

将其与EXEC所需的 SQL 进行对比;

DECLARE @SQL as nvarchar(128) = 'select ' + @Columns + ' from ' + 
            @TableName + ' where Status=' + char(39) + @Status + char(39)

...其中嵌入的 char(39) @Status 将使您的 SQL 无效,并可能创建 SQL 注入的可能性。例如,如果 @Status 设置为O'Reilly,则生成的 SQL 将是;

select acol,bcol,ccol FROM myTable WHERE Status='O'Reilly'
于 2013-02-06T05:38:45.900 回答
4

使用sp_executesql,您不必像那样构建查询。你可以这样声明:

DECLARE @SQL as nvarchar(128) = 'select ' + @Columns + ' from ' + 
@TableName + ' where Status=@eStatus'

这样,如果您的@Status价值来自您可以使用的用户@eStatus,而不必担心转义'。sp_executesql 使您能够以字符串形式将变量放入查询中,而不是使用连接。因此,您不必担心。

列和表变量仍然相同,但不太可能直接来自用户。

于 2013-02-06T05:37:40.370 回答
4

使用Exec您的 T-Sql 语句字符串中不能有占位符。

sp_executesql 为您提供了具有占位符并在运行时传递实际值的优势

于 2016-09-22T08:04:07.143 回答