我有几个上下文,其中表名或模式不是硬编码的,而是由管理员配置,或者更糟糕的是,从用户输入生成。
由于案例很简单(模式和表名用普通英语,没有数字或符号),因此只能禁止A-Z
和a-z
范围之外的任何字符来避免SQL注入。但是当应用程序必须处理任何Unicode字符时,这种方法很糟糕,因为它可以是模式或表的名称的一部分。
现在,如果SQL查询使用'['
和']'
来包含模式,表和列的名称,是否足以禁止名称中的']'
字符以避免SQL注入?
示例:
A'B是表格的有效名称。所以:
string tableNameFromUserInput = "A'B"; // Let's imagine it is a user input.
using (SqlCommand getEverything = new SqlCommand(
string.Format("select * from [dbo].[{0}]", tableNameFromUserInput),
sqlConnection)
{
// Do stuff.
}
完全有效,没有理由阻止单引号字符。
以下代码中是否存在SQL注入风险?
string tableName = UserInput.GetUnsafeInputFromUser();
// Search for ']' character only.
if (tableName.IndexOf(']') != -1)
{
throw new HackerDetectedException();
}
else
{
using (SqlCommand getEverything = new SqlCommand(
string.Format("select * from [dbo].[{0}]", tableNameFromUserInput),
sqlConnection)
{
// Do stuff.
}
}
修改
经过一些搜索,我发现的是Microsoft SQL中Delimited identifiers上的一篇文章。根据它:
标识符的主体可以包含当前代码页中的任何字符组合,但分隔字符本身除外。
顺便说一句,分隔标识符限制为128个字符。
所以要让它发挥作用:
']'
字符(或者更好,由']]'
替换;请参阅下面的Mark Byers答案。)答案 0 :(得分:3)
我认为那样安全。反斜杠等字符被视为文字字符,因此它们应安全地包含在表名中。我可以立即认为是一个问题的唯一字符是]
,你已经不允许这样做。顺便说一下,要将]
包含在表名中,需要将其写为]]
,因此不必完全拒绝它,而是可以tableName.Replace("]", "]]")
。
但为了安全起见,您应该按照建议使用白名单。为了在允许表名中的unicode字符的同时执行此操作,您可能需要考虑使用正则表达式@"^\w+$"
来验证表名,因为它也接受unicode字符。
答案 1 :(得分:2)
如果它只是选择sql,即你不打算保存任何更改,你可以在try块中的事务中运行sql命令并在finally块中回滚。
这样,您可以在代码级别确保不会从您的代码运行任何其他ddl,dml。只有选择的声明才会执行。
当您获取数据但未更新数据时,此特定的startegey会起作用。
try
{
//Run command in transaction.
}
catch (Exception ex)
{
// rollback transaction
}
finally
{
// rollback transaction
}
并且已经针对Sybase数据库进行了测试
答案 2 :(得分:2)
不确定您的内联SQL有多复杂,但为什么不通过QUOTENAME()从用户传递架构/表字符串来转义无效字符?
答案 3 :(得分:0)
我认为以下内容可能会破坏您的数据库,可能是OWASP中的以下内容:
'and 1 in (select min(name ) from master.dbo.sysdatabases where name >'.' ) --'
对于任何想要OWASP资源的人:
OWASP