加入收藏 | 设为首页 | 会员中心 | 我要投稿 安卓应用网 (https://www.0791zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 数据库 > MsSql > 正文

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

发布时间:2020-05-25 13:58:29 所属栏目:MsSql 来源:互联网
导读:代码必须做些什么来清理标识符(表,视图,列),而不是用双引号将它们包装起来,并在标识符名称中出现“double up”双引号?参考文献将不胜感激. 我继承了一个具有自定义对象关系映射(ORM)系统的代码库. SQL无法在应用程序中编写,但ORM仍必须最终生成要发送到SQL S

代码必须做些什么来清理标识符(表,视图,列),而不是用双引号将它们包装起来,并在标识符名称中出现“double up”双引号?参考文献将不胜感激.

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

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关于消毒.

如果必须调用QUOTENAME函数只是为了引用那些不需要SQL Server的大量流量的标识符.

关于SQL注入,ORM似乎已经过深思熟虑了.它位于C#中,早于nHibernate端口和实体框架等.所有用户输入都是使用ADO.NET SqlParameter对象发送的,它只是我在这个问题中关注的标识符名称.这需要适用于SQL Server 2005和2008.

2010-03-31更新

虽然应用程序不允许在查询中允许用户输入标识符名称,但ORM通过它对ORM样式读取和自定义查询具有的查询语法来执行.正是我试图最终阻止所有可能的SQL注入攻击的ORM,因为它非常小并且易于验证而不是所有应用程序代码.

查询界面的一个简单示例:

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(标识符)超过258个字符,则在分配给@delimitedIdentifier时将以静默方式截断它.当发生这种情况时,您可能会打开@delimitedIdentifier不正确转义的可能性.

微软的“安全软件开发人员”Bala Neerumalla有an MSDN article,它更深入地解释了这个主题.本文还包含了我发现的“关于如何在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 ]");
    }
}

(编辑:安卓应用网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读