SQL Server 存储过程中的 SQL 注入

sql injection in sql server stored procedure

提问人:Ram 提问时间:9/18/2018 最后编辑:Ram 更新时间:9/18/2018 访问量:148

问:

在下面的过程中,如何检查参数 @TECHNOLOGY,@CURE,@APPLICATION 的 SQL 注入?请帮忙

CREATE PROCEDURE [dbo].[SEARCH]
 @PRODUCTNAME NVARCHAR(500),
 @TECHNOLOGY NVARCHAR(200),
 @CURE NVARCHAR(200),
 @APPLICATION NVARCHAR(200)
AS
 SELECT DISTINCT PM.F_PRODUCT AS ID,
  PM.F_PRODUCT_NAME AS [NAME],
  PM.F_FORMAT AS FMT,
  PM.F_SUBFORMAT AS SFMT,
  STUFF((SELECT DISTINCT ', ' + CAST(F_LANGUAGE AS VARCHAR(200)) FROM T_PDF_MSDS PD
    WHERE PD.F_PRODUCT = PM.F_PRODUCT AND PD.F_FORMAT = PM.F_FORMAT AND PD.F_SUBFORMAT = PM.F_SUBFORMAT
    FOR XML PATH('')),1,1,'') AS LANG,
  PM.F_DOC_PATH AS DPATH,
  CONVERT(VARCHAR,PM.F_PUBLISHED_DATE,120) AS PDATE,
  SUBSTRING(PM.F_CUSTOM1, CHARINDEX(':',PM.F_CUSTOM1)+1, LEN(PM.F_CUSTOM1)) AS TECHNOLOGY,
  SUBSTRING(PM.F_CUSTOM2, CHARINDEX(':',PM.F_CUSTOM2)+1, LEN(PM.F_CUSTOM2)) AS CURE,
  SUBSTRING(PM.F_CUSTOM3, CHARINDEX(':',PM.F_CUSTOM3)+1, LEN(PM.F_CUSTOM3)) AS [APPLICATION],
  'PDF' AS DOC
 FROM T_PDF_MSDS PM
 WHERE
  --(@PRODUCTNAME IS NULL OR REPLACE(REPLACE(REPLACE(REPLACE(PM.F_PRODUCT_NAME,'™','|TM'),'®','|TS'),'©','|CP'),'°','|DEG')
   --LIKE REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@PRODUCTNAME,'[','\['),'_','\_'),'™','|TM'),'®','|TS'),'©','|CP'),'°','|DEG') ESCAPE '\')
 (@TECHNOLOGY = '-1' OR PM.F_CUSTOM1 LIKE '%' + @TECHNOLOGY + '%')
  AND (@CURE = '-1' OR PM.F_CUSTOM2 LIKE '%' + @CURE + '%')
  AND (@APPLICATION = '-1' OR PM.F_CUSTOM3 LIKE '%' + @APPLICATION + '%')
  AND PM.F_AUTHORIZED IN (-1,1,3)
 GROUP BY PM.F_PRODUCT, PM.F_PRODUCT_NAME, PM.F_FORMAT, PM.F_SUBFORMAT, PM.F_DOC_PATH, PM.F_PUBLISHED_DATE, PM.F_CUSTOM1, PM.F_CUSTOM2, PM.F_CUSTOM3
;

在上述过程中是否可以进行任何SQL注入?

sql-server t-sql 存储过程 sql 注入

评论

0赞 Peter B 9/18/2018
参见OWASP(Open Web Application Security Project):owasp.org/index.php/Testing_for_SQL_Injection_(OTG-INPVAL-005)。您的代码看起来很安全,因为它不使用动态创建的 SQL 语句。

答:

3赞 freefaller 9/18/2018 #1

SQL 注入通常是使用未经审查的输入构建 SQL 命令时。例如。。。

var sql = "SELECT * FROM MYTABLE WHERE MYCOLUMN = " + txtInput.Text;
var cmd = new SqlCommand(sql);
...

通过使用存储过程,可以有效地保护自己免受这种情况的影响。


感谢 @DanGuzman 的评论,他指出 SQL 注入确实可以通过存储过程实现,如果您以错误的方式调用它......

var sql = "EXEC MySproc '" + txtInput.Text + "'";
var cmd = new SqlCommand(sql);
...

正确的方法是确保使用参数化命令,例如...

var cmd = new SqlCommand("MySproc", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new SqlParameter("@MyParam", SqlDbType.NVarChar, 200));
cmd.Parameters["@MyParam"].Value = txtInput.Text;
...

作为对 OP 评论的回应(我觉得这在原始问题的范围内)......

通过在存储过程中使用动态 SQL,也有可能成为 SQL 注入的受害者。例如。。。

CREATE PROCEDURE [dbo].[MySproc]
   @MyParam NVARCHAR(200),
   @MyParam2 INT
AS
BEGIN
  DECLARE @SQL NVARCHAR(1000)
  SET @SQL = N'SELECT * FROM [MyTable] WHERE [MyColumn] = ''' + @MyParam + N''''
  EXEC sp_executesql @SQL
END

为了保护自己,您应该参数化您传递给 ...sp_executesql

DECLARE @SQL NVARCHAR(1000)
SET @SQL = N'SELECT * FROM [MyTable] WHERE [MyColumn] = @MyParamInner'
EXEC sp_executesql @SQL, N'@MyParamInner NVARCHAR(200)', @MyParam

请注意,不应在 where 子句上用引号将@MyParamInner括起来,即使它是基于字符的变量

如果您有多个值要传递,您可以将其更新为类似...

DECLARE @SQL NVARCHAR(1000)
SET @SQL = N'SELECT * FROM [MyTable] WHERE [MyColumn] = @MyParamInner AND [MyColumn2] = @MyParam2Inner'
EXEC sp_executesql @SQL, N'@MyParamInner NVARCHAR(200), @MyParam2Inner INT', @MyParam, @MyParam2

评论

0赞 Dan Guzman 9/18/2018
确实,除非过程代码中存在动态 SQL,否则不可能在存储过程中注入 SQL。但是,应用程序仍必须使用参数化命令正确调用存储过程,以避免 SQL 注入的风险。
0赞 freefaller 9/18/2018
@Dan,我很想知道如何在不使用参数化命令或动态 SQL 的情况下调用存储过程并实现 SQL 注入?(诚实的问题)
2赞 Dan Guzman 9/18/2018
公平的问题。.我已经看到在共享数据访问层中以这种方式构建的 proc 调用。根据 API,可以指定 CommandType.StoredProcedure,以确保在单独传递的命令文本和参数中仅指定 proc 名称。var sql = "EXEC dbo.YourProc '" + txtInput.Text + "';";
0赞 freefaller 9/18/2018
公平的答案!我可以把它添加到我的答案中吗?
1赞 Dan Guzman 9/18/2018
我很高兴看到你改进了你的答案,并使用了强类型参数而不是太强类型!AddWithValue