Корректный выход разграниченного identifers в SQL Server, не используя QUOTENAME

Есть ли что-либо еще, что код должен сделать для очистки идентификаторов (таблица, представление, столбец) кроме перенести их в двойные кавычки и "согнуть" двойные кавычки, существующие на имя идентификатора? Ссылки ценились бы.

Я наследовал кодовую базу, которая имеет реляционное пользовательским объектом отображение (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. Я нашел Выделенные идентификаторы (Механизм базы данных), и я также видел этот stackoverflow вопрос об очистке.

Если этому придется вызвать функцию QUOTENAME только для заключения в кавычки идентификаторов, который является большим трафиком к SQL Server, который не должен быть необходим.

ORM, кажется, вполне прилично продуман относительно Внедрения SQL. Это находится в C# и предшествует nHibernate порту и Платформе Объекта и т.д. Весь ввод данных пользователем отправляется с помощью объектов ADO.NET SqlParameter, это - просто имена идентификатора, которыми я обеспокоен в этом вопросе. Это должно работать над SQL Server 2005 и 2008.


Обновление 31.03.2010

В то время как приложение, как предполагается, не позволяет ввод данных пользователем для имен идентификатора в запросах, ORM делает через синтаксис запроса, который это имеет и для чтений ORM-стиля и для пользовательских запросов. Это - ORM, что я пытаюсь в конечном счете предотвратить все возможные Атаки с использованием кода на SQL, поскольку это является очень маленьким и легким проверить в противоположность всему коду приложения.

Простой пример интерфейса запросов:

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();
    return client;
}

Возможно, я должен посмотреть и видеть, как nHibernate защищает вход.

9
задан Community 23 May 2017 в 12:32
поделиться

2 ответа

Ваша функция QuoteName должна проверять длину, потому что функция T-SQL QUOTENAME определяет максимальную длину, которую она возвращает. Используя ваш пример:

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

Если QuoteName(identifier) длиннее 258 символов, он будет тихо усечен при присвоении @delimitedIdentifier. Когда это происходит, вы открываете возможность для @delimitedIdentifier быть неправильно экранированным.

Существует статья MSDN Бала Нирумалла, "разработчика программного обеспечения безопасности в Microsoft", в которой эта тема раскрывается более подробно. Статья также содержит самое близкое к "окончательной документации о том, как экранировать цитируемые идентификаторы в SQL Server":

Механизм экранирования - это просто удвоение вхождений правых квадратных скобок. Вам не нужно ничего делать с другими символами, включая левые квадратные скобки.

Вот код на 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 ]");
    }
}
20
ответ дан 4 December 2019 в 10:31
поделиться

Можно ли просто использовать разделители [и] вместо кавычек (одинарных или двойных)?

Идентификаторы никогда не должны содержать кавычек (если только вам не повезло больше, чем сейчас), поэтому вы удалите обычный коэффициент использования кавычек в именах и т. д.

Изменить:

Но если вызовы ORM уже параметризованы, вам не нужно об этом беспокоиться, не так ли? Использование [and] устраняет необходимость в сложном экранировании в строках C #

0
ответ дан 4 December 2019 в 10:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: