我使用 SQL Server 2012 并编写一个存储过程。
我想知道我的存储过程中是否存在 SQL 注入(inject)的可能性?
IF OBJECT_ID('Production.InsertProducts', 'P') IS NOT NULL
DROP PROCEDURE Production.InsertProducts
GO
CREATE PROCEDURE Production.InsertProducts
@productname AS NVARCHAR(40)
, @supplierid AS INT
, @categoryid AS INT
, @unitprice AS MONEY = 0
, @discontinued AS BIT = 0
AS
BEGIN
INSERT Production.Products (productname, supplierid, categoryid, unitprice, discontinued)
VALUES (@productname, @supplierid, @categoryid, @unitprice, @discontinued);
RETURN;
END;
GO
或者
IF OBJECT_ID('Production.InsertProducts', 'P') IS NOT NULL
DROP PROCEDURE Production.InsertProducts
GO
CREATE PROCEDURE Production.InsertProducts
@productname AS NVARCHAR(40)
, @supplierid AS INT
, @categoryid AS INT
, @unitprice AS MONEY = 0
, @discontinued AS BIT = 0
AS
BEGIN
Declare @Command NVArchar(Max) = 'INSERT Production.Products (productname, supplierid, categoryid, unitprice, discontinued)
VALUES (''' + @productname + ''',' + @supplierid + ',' + @categoryid + ',' + @unitprice + ',' + @discontinued + ');'
Execute(@Command);
RETURN;
END;
GO
或者
IF OBJECT_ID('Production.InsertProducts', 'P') IS NOT NULL
DROP PROCEDURE Production.InsertProducts
GO
CREATE PROCEDURE Production.InsertProducts
@productname AS NVARCHAR(40)
, @supplierid AS INT
, @categoryid AS INT
, @unitprice AS MONEY = 0
, @discontinued AS BIT = 0
AS
BEGIN
Declare @Command NVArchar(Max) = '
INSERT Production.Products (productname, supplierid, categoryid,
unitprice, discontinued)
VALUES ( @productname , @supplierid,@categoryid,@unitprice,@discontinued);'
Execute SP_ExecuteSql @Command,
' @productname NVARCHAR(40) , @supplierid INT , @categoryid INT
, @unitprice MONEY , @discontinued BIT ' ,
@productname= @productname,@supplierid=@supplierid,
@categoryid=@categoryid,@unitprice=@unitprice,@discontinued=@discontinued
RETURN;
END;
GO
这些查询中哪一个最好?
最佳答案
至于存储过程本身。
第一个没有机会进行 SQL 注入(inject),因为没有动态 SQL。
第三种方法没有 SQL 注入(inject)的机会,因为使用 sp_executesql
编译带有参数的查询,然后插入参数的值。从逻辑上讲,编译发生在参数替换之前,因此参数中的时髦字符串无法改变仅运行单个插入
的事实。
第二个很容易受到攻击,因为@productname
。其他参数是数字,我认为在字符串中包含数字不会导致漏洞。 (如果我错了,我相信有人会指出这是如何工作的引用。)此类参数存在风险,因为将来有人可能会将它们更改为字符串.
就安全性和最佳实践而言,第一个版本是最安全的。您甚至不必考虑是否存在漏洞。第三个是安全的,但看起来可能不安全。如果您完全担心 SQL 注入(inject),则应避免第二种情况。
至于return
的使用,我没有任何问题。它清楚地表明了程序员此时停止执行存储过程的意图。而且,事实上 SQL Server 的 documentation有一个多余的例子。存储过程确实返回值,始终是整数状态代码,我通常使用它们。
关于SQL Server存储过程和SQL注入(inject),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27219474/