gpt4 book ai didi

sql-server - 在不使用 QUOTENAME 的情况下正确转义 SQL Server 中的分隔标识符

转载 作者:行者123 更新时间:2023-12-02 10:44:55 24 4
gpt4 key购买 nike

除了将标识符(表、 View 、列)用双引号括起来以及标识符名称中存在的“双引号”之外,代码还必须执行其他操作吗? 引用文献将不胜感激。

我继承了一个具有自定义对象关系映射 (ORM) 系统的代码库。 SQL 无法在应用程序中编写,但 ORM 最终仍必须生成 SQL 并将其发送到 SQL Server。所有标识符都用双引号引起来。

string QuoteName(string identifier) 
{
return "\"" + identifier.Replace("\"", "\"\"") + "\"";
}

如果我在 SQL 中构建此动态 SQL,我将使用内置的 SQL Server QUOTENAME 函数:

declare @identifier nvarchar(128);
set @identifier = N'Client"; DROP TABLE [dbo].Client; --';

declare @delimitedIdentifier nvarchar(258);
set @delimitedIdentifier = QUOTENAME(@identifier, '"');

print @delimitedIdentifier;
-- "Client""; DROP TABLE [dbo].Client; --"

我还没有找到任何关于如何在 SQL Server 中转义带引号的标识符的明确文档。我找到了Delimited Identifiers (Database Engine)我还看到了this stackoverflow question关于 sanitizer 。

如果必须调用 QUOTENAME 函数只是为了引用标识符,那么 SQL Server 的流量就很大,这是不必要的。

ORM 似乎在 SQL 注入(inject)方面经过了深思熟虑。它是用 C# 编写的,早于 nHibernate 端口和 Entity Framework 等。所有用户输入都是使用 ADO.NET SqlParameter 对象发送的,它只是我在这个问题中关心的标识符名称。这需要在 SQL Server 2005 和 2008 上运行。

<小时/>

更新于2010年3月31日

虽然应用程序不应允许用户在查询中输入标识符名称,但 ORM 可以通过其用于 ORM 样式读取和自定义查询的查询语法来实现这一点。我试图最终阻止所有可能的 SQL 注入(inject)攻击的是 ORM,因为与所有应用程序代码相比,它非常小且易于验证。

查询接口(interface)的简单示例:

session.Query(new TableReference("Client")
.Restrict(new FieldReference("city") == "Springfield")
.DropAllBut(new FieldReference("first_name"));

ADO.NET 发送此查询:

exec sp_executesql N'SELECT "T1"."first_name" 
FROM "dbo"."Client" AS "T1"
WHERE "T1"."city" = @p1;',
N'@p1 nvarchar(30)',
N'Springfield';

也许思考一下 nHibernate 查询语言 (HQL) 中类似的情况会有所帮助:

using (ISession session = NHibernateHelper.OpenSession())
{
Client client = session
.CreateCriteria(typeof(Client)) \\ <-- TableReference in example above
.Add(Restrictions.Eq("city", "Springfield")) \\ <-- FieldReference above
.UniqueResult<Client>();
return client;
}

也许我应该看看 nHibernate 如何保护输入。

最佳答案

您的QuoteName函数需要检查长度,因为T-SQL QUOTENAME函数指定了它返回的最大长度。使用您的示例:

String.Format(@"declare @delimitedIdentifier nvarchar(258);
set @delimitedIdentifier = {0};", QuoteName(identifier));

如果 QuoteName(identifier) 长度超过 258 个字符,则在分配给 @delimitedIdentifier 时,它将被静默截断。发生这种情况时,@delimitedIdentifier 就有可能被不正确地转义。

an MSDN article “Microsoft 安全软件开发人员”Bala Neerumalla 更深入地解释了这个主题。该文章还包含我发现的最接近“有关如何在 SQL Server 中转义带引号的标识符的权威文档”的内容:

The escaping mechanism is simply doubling up the occurrences of right square brackets. You don't need to do anything with other characters, including left square brackets.

这是我当前使用的 C# 代码:

/// <summary>
/// Returns a string with the delimiters added to make the input string
/// a valid SQL Server delimited identifier. Brackets are used as the
/// delimiter. Unlike the T-SQL version, an ArgumentException is thrown
/// instead of returning a null for invalid arguments.
/// </summary>
/// <param name="name">sysname, limited to 128 characters.</param>
/// <returns>An escaped identifier, no longer than 258 characters.</returns>
public static string QuoteName(string name) { return QuoteName(name, '['); }

/// <summary>
/// Returns a string with the delimiters added to make the input string
/// a valid SQL Server delimited identifier. Unlike the T-SQL version,
/// an ArgumentException is thrown instead of returning a null for
/// invalid arguments.
/// </summary>
/// <param name="name">sysname, limited to 128 characters.</param>
/// <param name="quoteCharacter">Can be a single quotation mark ( ' ), a
/// left or right bracket ( [] ), or a double quotation mark ( " ).</param>
/// <returns>An escaped identifier, no longer than 258 characters.</returns>
public static string QuoteName(string name, char quoteCharacter) {
name = name ?? String.Empty;
const int sysnameLength = 128;
if (name.Length > sysnameLength) {
throw new ArgumentException(String.Format(
"name is longer than {0} characters", sysnameLength));
}
switch (quoteCharacter) {
case '\'':
return String.Format("'{0}'", name.Replace("'", "''"));
case '"':
return String.Format("\"{0}\"", name.Replace("\"", "\"\""));
case '[':
case ']':
return String.Format("[{0}]", name.Replace("]", "]]"));
default:
throw new ArgumentException(
"quoteCharacter must be one of: ', \", [, or ]");
}
}

关于sql-server - 在不使用 QUOTENAME 的情况下正确转义 SQL Server 中的分隔标识符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2547514/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com