public static bool TruncateTable(string dbAlias, string tableName)
{
string sqlStatement = string.Format("TRUNCATE TABLE {0}", tableName);
return ExecuteNonQuery(dbAlias, sqlStatement) > 0;
}
答案 0 :(得分:22)
打击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
现在,您可以将输入变量作为SQL参数传递给此查询。如果查询未返回任何行,则表示输入无效用作表。如果查询返回一行,则匹配,因此您可以更安全地使用它。
您还可以根据您定义的应用程序截断的特定表格列表验证表格名称,如@John Buchanan suggests。
即使在您的RDBMS中验证tableName
作为表名存在之后,我也建议分隔表名,以防您使用带有空格或特殊字符的表名。在Microsoft SQL Server中,默认标识符分隔符是方括号:
string sqlStatement = string.Format("TRUNCATE TABLE [{0}]", tableName);
现在,如果tableName
与真实表匹配,您只会面临SQL注入的风险,并且您实际上在表的名称中使用了方括号!
答案 1 :(得分: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
答案 2 :(得分:3)
如果您允许用户定义的输入通过tablename变量进入此函数,我不认为SQL注入是您唯一的问题。
更好的选择是通过自己的安全连接运行此命令,并且根本不给它任何SELECT权限。需要运行的所有TRUNCATE都是ALTER TABLE权限。如果你在SQL 2005以上,你也可以尝试在内部使用EXECUTE AS存储过程。
答案 3 :(得分:3)
CREATE OR REPLACE PROCEDURE truncate(ptbl_name IN VARCHAR2) IS
stmt VARCHAR2(100);
BEGIN
stmt := 'TRUNCATE TABLE '||DBMS_ASSERT.SIMPLE_SQL_NAME(ptbl_name);
dbms_output.put_line('<'||stmt||'>');
EXECUTE IMMEDIATE stmt;
END;
答案 4 :(得分:2)
使用存储过程。任何像样的数据库库(我使用的MS企业库)都将正确处理转义字符串参数。
另外,re:参数化查询:我更喜欢不必重新部署我的应用来修复数据库问题。在源代码中将查询存储为文字字符串会增加维护的复杂性。
答案 5 :(得分:1)
答案 6 :(得分:1)
使用参数化查询。
答案 7 :(得分:1)
还有一些其他帖子可以帮助SQL注入,所以我会提出这些,但另外要考虑的是你将如何处理这个权限。如果您授予用户db + owner或db_ddladmin角色以便它们可以截断表,那么仅仅避免标准SQL注入攻击是不够的。黑客可以发送其他可能有效的表名,但您不希望将其截断。
如果您要为特定表上的用户提供ALTER TABLE权限,那么您将允许截断它们,那么您的形状会更好一些,但它仍然比我在正常环境中允许的更多。 / p>
通常TRUNCATE TABLE不用于正常的日常应用程序使用。它用于ETL场景或数据库维护期间。我可以想象它将在前端应用程序中使用的唯一情况是,如果您允许用户加载特定于该用户的表以用于加载目的,但即便如此,我可能会使用不同的解决方案。
当然,在不知道你为什么使用它的具体细节的情况下,我不能断然说你应该重新设计,但如果我作为DBA得到这个请求,我会问开发人员很多的问题。
答案 8 :(得分:0)
在这个具体示例中,只有当表名来自外部源时,才需要保护SQL注入。
你为什么要允许这种情况发生? 如果你允许一些外部实体(最终用户,其他系统,什么?) 要命名要删除的表,为什么不给它们管理员权限。
如果要创建和删除表以为最终用户提供某些功能, 不要让它们直接为数据库对象提供名称。 除了SQL注入之外,你还会遇到名称冲突等问题。 而是自己生成真实的表名(例如DYNTABLE_00001,DYNTABLE_00002,...)并保留一个表格,将它们连接到用户提供的名称。
有关为DDL操作生成动态SQL的一些注意事项:
在大多数RDBMS中,您必须使用动态SQL并将表名作为文本插入。 要格外小心。
在所有ANSI兼容的RDBMS中使用带引号的标识符(MS SQL Server中的[],“”)。 这样可以更容易避免由无效名称引起的错误。
在存储过程中执行此操作并检查所有引用的对象是否有效。
不要做任何不可逆转的事情。例如。不要自动删除表。 您可以将它们标记为删除并通过电子邮件发送给您的DBA。 备份后,她会将它们删除。
如果可以,请避免使用它。如果你做不到,尽你所能,尽量减少对他人的权利 普通用户将拥有的(非动态)表格。
答案 9 :(得分:-2)
您可以使用SQLParameter传递tableName值。据我所知和测试,SQLParameter负责所有参数检查,从而禁用注入的可能性。
答案 10 :(得分:-4)
如果你不能使用参数化查询(你应该)......简单地替换'with'的所有实例都应该有效。
string sqlStatement = string.Format("TRUNCATE TABLE {0}", tableName.Replace("'", "''"));