我们有一个遗留应用程序不使用位置参数进行查询,并且到处都有SQL。决定(在我开始之前),由于用户输入可以包含撇号,因此应该为这些撇号手动转义每个字符串输入。
这是必要的原始代码(不是由我编写的),翻译成C#以便于消费:
private string _Escape(string input)
{
return input.Replace("'", "''");
}
private bool _IsValidLogin(string userName, string password)
{
string sql =
string.Format
(
@"SELECT COUNT(*) FROM UserAccounts
WHERE UserName = '{0}' AND Password = '{1}'",
_Escape(userName),
_Escape(password)
);
// ...
}
这看起来似乎可以在某种程度上被打破,但我不知道它是如何被用户输入利用的。假设用户输入未经过滤,直到达到_IsValidLogin
,并忘记密码似乎以纯文本形式存储。
支持它的解决方案是显而易见的 - 使用位置参数 - 但是我需要一些弹药来向管理人员证明这个代码为什么/如何不安全所以可以分配时间/ $来修复它。 / p>
注意:我假设这可能会被打破,但事实上可能并非如此。我不是SQL巨星。
注2:我已将此问题表达为与数据库无关,但如果您可以将此代码用于某个引擎,我欢迎您的贡献。
答案 0 :(得分:3)
可以用反斜杠来表示。
password = foo\' OR 1=1 --
变为:
password = foo\'' OR 1=1 --
查询:
"SELECT COUNT(*) FROM UserAccounts
WHERE UserName = '{0}' AND Password = 'foo\'' OR 1=1 --'"
--
此示例中是注释标记。
该解决方案假定程序仅过滤(重复)撇号。
答案 1 :(得分:1)
这是一篇非常好的文章:http://unixwiz.net/techtips/sql-injection.html
请参阅“查找表名称”。
答案 2 :(得分:0)
好吧,我看不出它的弱点。所以,让我们争论一个不同的原因,为什么它应该被改变 - 它是相当无比的。在MSSQL(我认为,大多数其他高端SQL服务器)中,解析查询,设计执行计划,然后存储查询和计划。如果再次请求exact
查询副本,则使用保存的执行计划。参数不会影响这一点,因此如果您使用参数,它将重用计划;如果您嵌入文本,它永远不会。