8

可能重复:
我可以通过转义单引号并用单引号包围用户输入来防止 SQL 注入吗?

我们有一个不使用位置参数进行查询的遗留应用程序,而且到处都有 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,并且忘记密码似乎是以纯文本形式存储的。

永久支持它的解决方案是显而易见的——使用位置参数——但我需要一些弹药来向管理层展示为什么/如何这段代码不安全,因此可以分配时间/美元来修复它。

注意:我假设这可以被打破,但实际上可能并非如此。我不是 SQL 超级明星。

注意 2:我已将此问题表达为与数据库无关,但如果您可以将此代码用于某个引擎,我欢迎您的贡献。

4

2 回答 2

3

它可以被反斜杠所利用。

password = foo\' OR 1=1 --

变成:

password = foo\'' OR 1=1 --

查询:

"SELECT COUNT(*) FROM UserAccounts
                WHERE UserName = '{0}' AND Password = 'foo\'' OR 1=1 --'"

--是本例中的注释标记。

该解决方案假定程序仅过滤(重复)撇号。

于 2010-03-04T14:44:35.673 回答
0

好吧,我看不出它是脆弱的。所以,让我们争论一个应该改变它的不同原因——它相当低效。在 MSSQL(以及,我认为,大多数其他高端 SQL 服务器)中,查询被解析,执行计划被设计,然后查询和计划被存储。如果exact再次请求查询的副本,则使用保存的执行计划。参数不影响这个,所以如果你使用参数,它会重用计划;如果你嵌入文本,它永远不会。

于 2010-03-04T14:49:15.230 回答