如何保护此函数免受SQL注入?

dwb*_*nks 10 c# sql sql-injection

public static bool TruncateTable(string dbAlias, string tableName)
{
    string sqlStatement = string.Format("TRUNCATE TABLE {0}", tableName);
    return ExecuteNonQuery(dbAlias, sqlStatement) > 0;
}
Run Code Online (Sandbox Code Playgroud)

Bil*_*win 23

打击SQL注入的最常见建议是使用SQL查询参数(此线程上有几个人建议它).

在这种情况下,这是错误的答案.您不能在DDL语句中为表名使用SQL查询参数.

SQL查询参数只能用于替代SQL表达式中的文字值.这是SQL的每个实现的标准.

当您拥有表名时,我建议防止SQL注入是针对已知表名列表验证输入字符串.

您可以从以下位置获取有效表名称列表INFORMATION_SCHEMA:

SELECT table_name 
FROM INFORMATION_SCHEMA.Tables 
WHERE table_type = 'BASE TABLE'
  AND table_name = @tableName
Run Code Online (Sandbox Code Playgroud)

现在,您可以将输入变量作为SQL参数传递给此查询.如果查询未返回任何行,则表示输入无效用作表.如果查询返回一行,则匹配,因此您可以更安全地使用它.

您还可以根据您定义的特定表的列表验证表名,以便您的应用截断,正如@John Buchanan 建议的那样.

即使在验证了tableName作为RDBMS中的表名存在之后,我也建议分隔表名,以防您使用带有空格或特殊字符的表名.在Microsoft SQL Server中,默认标识符分隔符是方括号:

string sqlStatement = string.Format("TRUNCATE TABLE [{0}]", tableName);
Run Code Online (Sandbox Code Playgroud)

现在,如果tableName匹配真实表,您只会面临SQL注入的风险,并且您实际上在表的名称中使用方括号!

  • 验证可能的输入.+1 (2认同)

Joh*_*nan 6

据我所知,您不能使用参数化查询来执行DDL语句/指定表名,至少不能在Oracle或Sql Server中使用.我要做的,如果我必须有一个疯狂的TruncateTable函数,必须安全sql注入将是一个存储过程,检查输入是一个可以安全截断的表.


-- Sql Server specific!
CREATE TABLE TruncableTables (TableName varchar(50))
Insert into TruncableTables values ('MyTable')

go

CREATE PROCEDURE MyTrunc @tableName varchar(50)
AS
BEGIN

declare @IsValidTable int
declare @SqlString nvarchar(50)
select @IsValidTable = Count(*) from TruncableTables where TableName = @tableName

if @IsValidTable > 0
begin
 select @SqlString = 'truncate table ' + @tableName
 EXECUTE sp_executesql @SqlString
end
END
Run Code Online (Sandbox Code Playgroud)