Что касается внедрения SQL , я полностью понимаю необходимость параметризации string
параметра; это одна из старейших уловок в книге. Но когда можно оправдать отсутствие параметризации SqlCommand
? Считаются ли какие-либо типы данных "безопасными" для отказа от параметризации?
Например: Я не считаю себя в любом месте рядом с экспертом в SQL, но я не могу думать о каких - либо случаях , когда это было бы потенциально уязвимы к SQL инъекции , чтобы принять bool
или int
и просто сцепить его прямо в запросе.
Верно ли мое предположение, или это потенциально может привести к серьезной уязвимости системы безопасности в моей программе?
Для пояснения этот вопрос помечен C #который является строго типизированным языком; когда я говорю «параметр», думаю, что-то вроде public int Query(int id)
.
источник
Ответы:
Я думаю, что это безопасно ... технически , но это ужасная привычка. Вы действительно хотите писать такие запросы?
Это также оставляет вас уязвимым в ситуации, когда тип меняется с целого числа на строку (подумайте о номере сотрудника, который, несмотря на его название, может содержать буквы).
Итак, мы изменили тип EmployeeNumber с
int
наstring
, но забыли обновить наши запросы sql. К сожалению.источник
AddWithValue
уже прекратить употреблять ? blogs.msmvps.com/jcoehoorn/blog/2014/05/12/…AddWithValue
если у вас нет сопоставления типов базы данных как части динамического построения оператора. Я предполагаю, что у вас есть список целевых столбцов, и как часть словаря, вы можете иметь типы, если хотите. В противном случае просто получите удар производительности. В конце концов, я думаю, это просто хорошая информация.AddWithValue
уже прекратить употреблять ?" должны действительно быть « , если вы знаете тип, то вы должны воздерживаться от использованияAddWithValue
.При использовании сильно типизированных платформы на компьютере управления (например , веб - сервер), вы можете предотвратить инъекции кода для запросов только
bool
,DateTime
илиint
(и другие числовые) значения. Беспокойство вызывает проблемы с производительностью, вызванные принудительной повторной компиляцией каждого запроса сервером sql и предотвращением получения хорошей статистики о том, какие запросы выполняются с какой частотой (что вредит управлению кешем).Но эта часть «на компьютере, которым вы управляете» важна, потому что в противном случае пользователь может изменить поведение, используемое системой для генерации строк из этих значений, чтобы включить произвольный текст.
Я также люблю думать о долгосрочной перспективе. Что происходит, когда сегодняшняя устаревшая строго типизированная база кода переносится через автоматический перевод на новый динамический язык, и вы внезапно теряете проверку типов, но еще не имеете всех необходимых модульных тестов для динамического кода ?
На самом деле нет веских причин не использовать параметры запроса для этих значений. Это правильный способ сделать это. Идите вперед и жестко закодируйте значения в строку sql, если они действительно являются константами, но в противном случае почему бы просто не использовать параметр? Не то чтобы это было сложно.
В конечном счете, я бы не назвал это ошибкой как таковой, но я бы назвал это запахом : то, что само по себе не является ошибкой, но является убедительным признаком того, что ошибки поблизости или будут в конечном итоге. Хороший код не оставляет запаха, и любой хороший инструмент статического анализа отметит это.
Я добавлю, что это, к сожалению, не тот аргумент, который можно выиграть сразу. Похоже, ситуация, когда «быть правым» уже недостаточно, и наступать на пальцы ног ваших коллег, чтобы решить эту проблему самостоятельно, вряд ли будет способствовать хорошей командной динамике; в конечном итоге это может больше навредить, чем помочь. Лучшим подходом в этом случае может быть продвижение использования инструмента статического анализа. Это придаст законность и доверие усилиям, направленным на исправление существующего кода и исправлению его.
источник
DateTime
илиint
В некоторых случаях МОЖНО выполнить атаку с использованием SQL-инъекции с непараметризованными (конкатенированными) переменными, отличными от строковых значений - см. Эту статью Джона: http://codeblog.jonskeet.uk/2014/08/08/the-bobbytables -культура / .
Дело в том, что при
ToString
вызове какой-то настраиваемый поставщик культуры может преобразовать нестроковый параметр в свое строковое представление, которое вводит некоторый SQL в запрос.источник
int
s?»CultureInfo
трудно понять, зачем вам все равно понадобится SQL-инъекция.Это не безопасно даже для типов нестроковых. Всегда используйте параметры. Период.
Рассмотрим следующий пример кода:
На первый взгляд код выглядит безопасным, но все изменится, если вы внесете некоторые изменения в региональные настройки Windows и добавите инъекцию в коротком формате даты:
Теперь итоговый текст команды выглядит так:
То же самое можно сделать и для
int
типа, поскольку пользователь может определить собственный отрицательный знак, который можно легко заменить на SQL-инъекцию.Можно было бы возразить, что вместо текущей культуры следует использовать инвариантную культуру, но я видел подобные конкатенации строк много раз, и их довольно легко пропустить при объединении строк с использованием объектов
+
.источник
int
типе?«ВЫБРАТЬ * ИЗ Table1 WHERE Id =» + intVariable.ToString ()
Безопасность
Это нормально.
Злоумышленники не могут ничего ввести в вашу типизированную переменную int.
Производительность
не в порядке.
Лучше использовать параметры, чтобы запрос был скомпилирован один раз и кэширован для следующего использования. В следующий раз, даже с другими значениями параметров, запрос кешируется и не требует компиляции на сервере базы данных.
Стиль кодирования
Плохая практика.
«ВЫБРАТЬ * ИЗ продукта, ГДЕ Id =» + TextBox1.Text
Хотя это не ваш вопрос, но может быть полезно для будущих читателей:
Катастрофа безопасности !
Даже если
Id
поле является целым числом, ваш запрос может подвергнуться SQL-инъекции. Предположим, у вас есть запрос в вашем приложении"SELECT * FROM Table1 WHERE Id=" + TextBox1.Text
. Злоумышленник может вставить его в текстовое поле,1; DELETE Table1
и запрос будет следующим:Если вы не хотите использовать здесь параметризованный запрос, вам следует использовать типизированные значения:
Ваш вопрос
Я думаю, что изменение этих кодов - не пустая трата времени. Действительно рекомендуется изменение!
Если ваш коллега использует переменные типа int, это не представляет угрозы для безопасности, но я думаю, что изменение этих кодов не пустая трата времени, и действительно рекомендуется изменить эти коды. Это делает код более читаемым, более удобным в обслуживании и ускоряет выполнение.
источник
.ToString()
определяется элементом конфигурации операционной системы, который легко изменить, включив в него произвольный текст.На самом деле есть два вопроса в одном. И вопрос из заголовка имеет мало общего с опасениями, выраженными ОП в комментариях впоследствии.
Хотя я понимаю, что для OP важен именно их конкретный случай, для читателей из Google важно ответить на более общий вопрос, который можно сформулировать так: «Конкатенация так же безопасна, как и подготовленные утверждения, если я убедился что каждый литерал, который я объединяю, безопасен? ". Итак, я хотел бы сосредоточиться на последнем. И ответ
Определенно нет.
Объяснение не такое прямое, как хотелось бы большинству читателей, но я постараюсь изо всех сил.
Некоторое время я размышлял над этим вопросом, и в результате появилась статья (хотя и основанная на среде PHP), в которой я попытался подвести итоги. Мне пришло в голову, что вопрос защиты от SQL-инъекций часто ускользает от некоторых связанных, но более узких тем, таких как экранирование строк, приведение типов и тому подобное. Хотя некоторые меры можно считать безопасными, если их принимать сами по себе, не существует системы или простого правила, которому следовало бы следовать. Это делает его очень скользким, слишком сильно отнимая у разработчика внимание и опыт.
Вопрос о внедрении SQL нельзя упростить до какой-то конкретной синтаксической проблемы. Он шире, чем раньше думал средний разработчик. Это тоже методологический вопрос. Это не только «какое именно форматирование мы должны применить», но и « как это должно быть сделано».
(С этой точки зрения статья Джона Скита, процитированная в другом ответе, работает скорее плохо, чем хорошо, поскольку она снова придирается к какому-то крайнему случаю, концентрируется на конкретной проблеме синтаксиса и не может решить проблему в целом.)
Когда вы пытаетесь решить вопрос о защите не в целом, а как набор различных синтаксических проблем, вы сталкиваетесь с множеством проблем.
В отличие от этого беспорядка, заранее подготовленные утверждения - это действительно Святой Грааль:
(Подумав дальше, я обнаружил, что текущего набора заполнителей недостаточно для реальных жизненных потребностей, и его необходимо расширять как для сложных структур данных, таких как массивы, так и даже для ключевых слов или идентификаторов SQL, которые иногда приходится добавлять к запрос тоже динамически, но разработчик остается безоружным для такого случая и вынужден вернуться к конкатенации строк, но это уже другой вопрос).
Интересно, что полемика по этому вопросу вызвана очень противоречивой природой Stack Overflow. Идея сайта состоит в том, чтобы использовать конкретные вопросы пользователей, которые задают напрямую, для достижения цели создания базы данных ответов общего назначения, подходящей для пользователей, которые приходят из поиска . Идея сама по себе неплохая , но она терпит неудачу в такой ситуации: когда пользователь задает очень узкий вопрос , в частности, чтобы получить аргумент в споре с коллегой (или решить, стоит ли рефакторинг кода). Хотя большинство опытных участников пытаются написать ответ, помня о миссии Stack Overflow в целом, что делает их ответ интересным для как можно большего числа читателей, а не только для OP.
источник
Давайте не будем думать только о безопасности или типобезопасности.
Причина, по которой вы используете параметризованные запросы, заключается в повышении производительности на уровне базы данных. С точки зрения базы данных параметризованный запрос - это один запрос в буфере SQL (если использовать терминологию Oracle, хотя я полагаю, что все базы данных имеют аналогичную внутреннюю концепцию). Таким образом, база данных может хранить в памяти определенное количество запросов, подготовленных и готовых к выполнению. Эти запросы не нужно анализировать, и они будут выполняться быстрее. Часто выполняемые запросы обычно находятся в буфере и не нуждаются в синтаксическом анализе каждый раз, когда они используются.
если
Кто-то не использует параметризованные запросы. В этом случае буфер постоянно очищается потоком почти идентичных запросов, каждый из которых должен быть проанализирован и запущен ядром базы данных, и производительность страдает от всех возможных, поскольку даже часто выполняемые запросы в конечном итоге повторно анализируются много раз. день. Я зарабатывал себе на жизнь настройкой баз данных, и это был один из самых больших источников низко висящих фруктов.
СЕЙЧАС
Чтобы ответить на ваш вопрос, ЕСЛИ ваш запрос имеет небольшое количество различных числовых значений, вы, вероятно, не вызовете проблем и на самом деле можете бесконечно улучшить производительность. ЕСЛИ, однако, потенциально существуют сотни значений и запрос часто вызывается, вы собираетесь повлиять на производительность вашей системы, поэтому не делайте этого.
Да, вы можете увеличить буфер SQL, но в конечном итоге это всегда происходит за счет других, более важных применений памяти, таких как кеширование индексов или данных. Мораль, используйте параметризованные запросы довольно строго, чтобы вы могли оптимизировать свою базу данных и использовать больше памяти сервера для вещей, которые имеют значение ...
источник
Чтобы добавить некоторую информацию к ответу Maciek:
Информацию о культуре стороннего приложения .NET легко изменить, вызвав основную функцию сборки путем отражения:
Это работает, только если основная функция BobbysApp является общедоступной. Если Main не является общедоступным, вы можете вызывать другие общедоступные функции.
источник
На мой взгляд, если вы можете гарантировать, что параметр, с которым вы работаете, никогда не будет содержать строку, это безопасно, но я бы не стал этого делать в любом случае. Кроме того, вы увидите небольшое снижение производительности из-за того, что вы выполняете конкатенацию. Я хотел бы задать вам вопрос: почему вы не хотите использовать параметры?
источник
Это нормально, но никогда не безопасно .. и безопасность всегда зависит от входных данных, например, если входным объектом является TextBox, злоумышленники могут сделать что-то сложное, поскольку текстовое поле может принимать строку, поэтому вам нужно поставить какую-то проверку / преобразование чтобы иметь возможность предотвратить неправильный ввод пользователей. Но дело в том, что это небезопасно. Вот так просто.
источник
Нет, таким образом можно получить атаку с помощью SQL-инъекции. Я написал старую статью на турецком, в которой показано, как здесь . Пример статьи в PHP и MySQL, но концепция работает одинаково в C # и SQL Server.
В основном вы нападаете следующим образом. Допустим, у вас есть страница, на которой отображается информация в соответствии с целочисленным значением id. Вы не параметризовали это значение, как показано ниже.
Хорошо, я предполагаю, что вы используете MySQL, и я атакую следующим образом.
Обратите внимание, что здесь введенное значение не является строкой. Мы меняем значение char на int с помощью функции ASCII. Вы можете сделать то же самое в SQL Server, используя «CAST (YourVarcharCol AS INT)».
После этого я использую функции длины и подстроки, чтобы узнать имя вашей базы данных.
Затем, используя имя базы данных, вы начинаете получать имена таблиц в базе данных.
Конечно, вы должны автоматизировать этот процесс, поскольку вы получаете только ОДИН символ на запрос. Но вы легко можете это автоматизировать. В моей статье показан один пример в watir . Использование только одной страницы и не параметризованного значения ID. Я могу узнать имя каждой таблицы в вашей базе данных. После этого я могу искать важные таблицы. На это потребуется время, но это выполнимо.
источник
public void QuerySomething(int id) { // this will only accept an integer }
Что ж ... одно можно сказать наверняка: безопасность - это НЕ нормально, когда вы объединяете строку (взятую пользователем) со строкой команды SQL. Не имеет значения, относится ли предложение where к Integer или к любому типу; инъекции могут произойти.
В SQL Injection важен тип данных переменной, которая использовалась для получения значения от пользователя.
Предположим, у нас есть целое число в предложении where и:
пользовательская переменная - это строка. Тогда хорошо, это не очень просто ввести (используя UNION), но очень легко обойти, используя атаки типа 'OR 1 = 1' ...
Если пользовательская переменная является целым числом. С другой стороны, мы можем «проверить» прочность системы, пройдя тестирование с необычно большими числами на сбои системы или даже на скрытое переполнение буфера (в последней строке) ...;)
Возможно, параметры запросов или (даже лучше - imo) хранимых процедур не являются 100% безопасными для угроз, но они являются наименее необходимой мерой (или элементарной, если хотите) для их минимизации.
источник