Это дырявая абстракция? - PullRequest
       9

Это дырявая абстракция?

0 голосов
/ 28 февраля 2009

Является ли указание имени поля в промежуточном уровне негерметичной абстракцией?

Мне кажется слишком громоздким создавать отдельную функцию для каждого поля, даже если оно генерируется кодом.

        public bool Assortment_IsValueExistingOnOtherRecord(
            Dictionary<string, object> exceptPkColumns,
            string field, object value
            )
        {
            var c = Connect();

            var dt = new DataTable();

            string sanitizedField = field.Replace("'","");

            var daAssortment = new SqlDataAdapter(
               string.Format(
@"SELECT 1 FROM assortment
WHERE 
/* do I violate any good programming practice here? */ [{0}] = @value 
AND NOT (assortment_id = @assortment_id)",  field), c);

            daAssortment.SelectCommand.Parameters.Add("assortment_id", exceptPkColumns["assortment_id"]);
            daAssortment.SelectCommand.Parameters.Add("value", value);
            daAssortment.Fill(dt);

            return dt.Rows.Count == 1;
        } 

Ответы [ 4 ]

1 голос
/ 28 февраля 2009

С точки зрения инкапсуляции нет ничего плохого в том, что вы написали.

Однако, как намекал «Дэвид Б» (он немного об этом говорил), есть некоторые проблемы безопасности, о которых вам необходимо знать.

Динамический SQL, который вы генерируете, подвержен так называемой «атаке SQL-инъекцией». Представьте, например, что значением поля была следующая строка:

assortment_id] = 0 and assortment_id = 1 
delete from assortment
select 1 from assortment where [assortment_id

это приведет к тому, что база данных выполнит 3 запроса:

  1. Пустой запрос на выборку, который не дал результатов
  2. Запрос на удаление, который удалял все в ассортиментной таблице
  3. запрос реального выбора

Это, очевидно, может вызвать некоторые проблемы.

Если значение "field" когда-либо указано с помощью:

  1. Поле интерфейса пользователя
  2. Отправка формы веб-страницы
  3. Из клиента веб-службы
  4. Загружен из файла на диске
  5. Или любым другим способом, кроме постоянного значения, указанного вами в коде

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

1 голос
/ 28 февраля 2009
[{0}] = @value

Это нормально, если приняты соответствующие меры. «Санитарная обработка» не входит в число этих мер.

Вариант 1. У вас есть неявное доверие к провайдеру, так что вы знаете, что он никогда не будет связываться с вами? Например, если вы (как автор этого модуля) являетесь поставщиком данной области, вы можете доверять себе.

Вариант 2. Можете ли вы сделать enum / lookup, который отображает запрошенные поля в строки? Тогда «клиент» этого кода может только запрашивать вещи в перечислении, и вы (автор этого модуля) становитесь поставщиком полей, сопоставляя запрашиваемое значение перечисления с известной строкой.

Вариант 3: Если поля меняются со временем и вы не хотите блокироваться с помощью enum, можете ли вы отправить строковое значение в базу данных для подтверждения?

SELECT name
FROM syscolumns
WHERE name = @name

Это сопоставляет предоставленное имя с известной строкой, которая поступает из базы данных и должна быть безопасной.

0 голосов
/ 28 февраля 2009

Да. Утечка всех абстракций.

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

0 голосов
/ 28 февраля 2009

Используйте выражение, и вы получите безопасность во время компиляции (и Sql runtime):

public bool Assortment_IsValueExistingOnOtherRecord<TValue>(
        Dictionary<string, object> exceptPks,
        Expression<Func<Assortment, TValue>> expression,
        TValue value
        )

    propExp = expression.Body as MemberExpression;
    if (propExp == null) throw new ArgumentException();
    string field = propExp.Member.Name; 

    /* blah, blah */
}

/* Calling code */
bool exists = Assortment_IsValueExistingOnOtherRecord(
                exceptPKs, 
                (a => a.Property1),
                "property1Value"
              );

С помощью общего значения TValue вы также получаете строго типизированное значение, соответствующее свойству - избегая случайного «мертвого» разума, который сделает для вас ваша СУБД.

Вы можете иметь полное выражение равенства или даже добавить поддержку <и> - но тогда вы просто придумаете LINQ для доморощенного ORM. ;)

Кроме того, excPK кажется немного странным ... но, возможно, это имеет смысл в контексте?

...