Инъекция SQL без веба - PullRequest
       20

Инъекция SQL без веба

21 голосов
/ 04 февраля 2009

Кажется, есть некоторая истерия по поводу атак с использованием SQL-инъекций. Совсем недавно здесь

Как вернуть значение в одном поле на основе значения поиска в другом поле

Если я создаю макрос в Excel, который подключается к базе данных Access, действительно ли я должен беспокоиться о внедрении SQL? Это не в Интернете, оно используется в моем офисе (вы, ребята, помните десктопы, верно?). Я не обеспокоен тем, что мои коллеги собираются саботировать меня. Если они достаточно умны, чтобы делать инъекции SQL, разве они не достаточно умны, чтобы взломать мой пароль надстройки и просто изменить код?

Ответы [ 15 ]

26 голосов
/ 04 февраля 2009

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

19 голосов
/ 04 февраля 2009

Вы никогда не знаете, когда в таблицах Бобби будет использоваться ваше слово macro:

xkcd

19 голосов
/ 04 февраля 2009

SQL-инъекция - это не просто угроза безопасности, но и источник ошибок.

Вы уверены , что ни в одной из ваших записей никогда не будет апостофа (')?

INSERT INTO NAMES (FIRSTNAME, LASTNAME) VALUES('Jack', 'O'Neill')

В этом случае у вас есть ошибка, хотя никто не хотел взломать вашу систему.

8 голосов
/ 07 февраля 2009

Я хотел бы расширить комментарий, который я сделал выше в ответ на сообщение, в котором говорится о том, как использовать оператор SELECT в MS Access. Имейте в виду, что это не обобщенные комментарии о том, как защитить от внедрения SQL, но они относятся конкретно к программированию в MS Access.

Я никогда не видел ни одного примера кода для Access, который позволил бы использовать тот тип взлома SELECT, который был описан в тот день. Причина этого заключается в том, что почти никогда не бывает ситуаций, когда вы использовали бы такие простые методы для сбора критериев без некоторой проверки входных данных где-то по пути, не для того, чтобы избежать внедрения SQL, но чтобы избежать ошибок, вызванных неверным SQL.

Вот код, реализующий простейшую версию этого:

Public Sub TestSQLExploit()
  Dim strSQL As String

  strSQL = "SELECT tblInventory.* FROM tblInventory WHERE InventoryID = "
  strSQL = strSQL & InputBox("Enter InventoryID")
  Debug.Print strSQL
End Sub

Таким образом, передача «10036 или« a »=« a »» приводит к следующему SQL:

SELECT tblInventory.*
FROM tblInventory
WHERE InventoryID=10036 Or 'a'='a'

И это определенно не хорошо!

Теперь я бы никогда не написал свой код таким образом, потому что я всегда хочу учитывать несколько значений. Вместо этого, если бы я использовал функцию InputBox () для сбора пользовательского ввода (чего я, честно говоря, никогда не делаю, поскольку его слишком сложно проверить), я бы использовал Application.BuildCriteria для написания предложения WHERE, поскольку это позволило бы мне обрабатывать несколько критериев значений. Это приведет к следующему коду:

Public Sub TestSQLExploit1()
  Dim strSQL As String
  Dim strWhere As String

  strSQL = "SELECT tblInventory.* FROM tblInventory "
  strWhere = "WHERE " & Application.BuildCriteria("tblInventory.InventoryID", _
      dbLong, InputBox("Enter InventoryID"))
  strSQL = strSQL & strWhere
  Debug.Print strSQL
End Sub

Честно говоря, я думал, что Application.BuildCriteria выдаст ошибку на этом, но это не так, и при передаче "10036 или 'a' = 'a'" выдает точно такой же SQL. А из-за того, как работает служба выражений Jet, она будет широко открыта, как вы говорите.

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

Я никогда не видел примеров кода доступа для такого рода операций, в которых не рекомендуется использовать параметризованный SQL (что, конечно, позволило бы избежать проблемы) или интерфейс Query-By-Form. Я обычно не использую сохраненные запросы параметров в Access, потому что мне нравится писать свои сохраненные запросы, чтобы их можно было везде использовать. Это означает, что в большинстве случаев они не имеют предложений WHERE, которые имеют критерии, которые меняются во время выполнения. Когда я использую эти сохраненные запросы, я предоставляю предложение WHERE для соответствующей ситуации, будь то в качестве источника записей в форме или источника строк для списка или раскрывающегося списка.

Теперь, суть в том, что я не запрашиваю ввод данных в этих случаях, а рисую значения критериев из объектов Access, таких как элемент управления в форме. Теперь, в большинстве случаев, это будет контроль над формой, которая имеет только одну цель - собрать критерии для какой-либо формы фильтрации. В этой форме не будет никаких непроверенных полей с произвольным текстом - поля даты будут иметь входные маски (которые будут ограничивать ввод действительными датами), а поля с ограниченным числом допустимых значений будут иметь типы элементов управления, ограничивающие варианты выбора допустимыми данные. Обычно это что-то вроде выпадающего списка или группы параметров.

Причиной такого дизайна является не обязательно избегать SQL-инъекций (хотя это предотвратит это), но чтобы убедиться, что пользователь не разочарован введением недопустимых критериев, которые не дадут результатов.

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

Если у меня есть текстовое поле, в котором пользователь вводит "fent * или 'a' = 'a'", и я использую это в предложении WHERE:

WHERE tblDonor.LName Like "fent* or 'a' = 'a'"

В результате ничего не найдено. Если пользователь ввел «fent * или a = a», он все равно не будет работать, потому что это текстовое поле, и я использую двойные кавычки вокруг него. Если пользователь ввел:

fent* or "a" = "a"

это тоже сломается, потому что когда мой код помещает двойные кавычки, предложение WHERE будет недействительным.

Теперь, когда мы просто используем ввод и заключаем в него двойные кавычки, ясно, что ввод этого:

" Or "fent*" or "a" = "a" Or "

приведет к:

WHERE tblDonor.LName Like "" Or "fent*" or "a" = "a" Or ""

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

WHERE tblDonor.LName Like "? Or ?fent*? or ?a? = ?a? Or ?*"

Это не вернет никаких строк.

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

======

Некоторые выводы:

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

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

На практике это означает, что если вы хотите собрать несколько критериев, вам нужно сделать это так, чтобы пользователь мог выбирать только из предварительно выбранных значений. Самый простой способ сделать это с помощью списка с множественным выбором (или пары из них с помощью кнопок ADD >> и << REMOVE между ними). ​​</p>

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

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

Итак, мой вынос на все это:

  1. никогда не используйте InputBox () для сбора критериев (этого я уже избегаю).

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

  3. при использовании текстового поля для сбора строковых данных обрабатывайте его как единый критерий независимо от того, что вводит пользователь.

Это означает, что у меня есть некоторые приложения, где пользователь может ввести «Или» = «a» вместе с действительным критерием и вернуть все строки, но в этих приложениях это просто не проблема, поскольку данные не являются конфиденциальными.

Но это хорошее напоминание мне не быть самодовольным. Я думал, что Application.BuildCriteria защитит меня, но теперь понимаю, что служба выражений Jet слишком проста в том, что она принимает в предложении WHERE.

2009/12/08 РЕДАКТИРОВАТЬ: Только что нашел эти ссылки на SQL-инъекции в MS Access. Все они нацелены на веб-инъекцию, поэтому не могут напрямую применяться к обсуждению не-веб-SQL-инъекции (многие из них были бы пустой тратой времени в интерактивном доступе, поскольку у вас уже есть доступ к большей части информации, которая является грубой принудительно (например, информация о файловой системе, путях, исполняемых файлах и т. д.), но многие из методов также будут работать в приложении Access. Кроме того, выполнение из Access открывает множество функций, которые не могут быть запущены из ODBC / OLEDB. Пища для размышлений.

4 голосов
/ 04 февраля 2009

Физическая безопасность - это всегда первая линия защиты в безопасности данных. Если ваше приложение будет распространяться только внутри офиса, а доступ к данным недостаточен для того, чтобы кто-то мог пойти на неприятности и за счет кражи и взлома, вы можете придерживаться более низкого стандарта безопасности, чем тот, который вы использовали бы для внешнего стоящее веб-приложение.

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

Хорошее эмпирическое правило - спросите себя: если бы я, обладая полным знанием этого продукта, хотел использовать его, чтобы навредить моей компании, какой ущерб я мог бы нанести? Затем обеспечьте достаточную безопасность, чтобы довести это число до приемлемых уровней.

4 голосов
/ 04 февраля 2009

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

4 голосов
/ 04 февраля 2009

Как разработчик, вы несете ответственность, если не полностью, то хотя бы частично, за безопасность данных, хранящихся в вашем приложении.

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

В конце концов, вы не хотите быть тем, кто должен объяснить боссу, куда ушли прошлогодние показатели продаж.

3 голосов
/ 04 февраля 2009

Нет. (Да.) Да. :)

Часто я вижу, как разработчики тратят драгоценные ресурсы на укрепление «входной двери», только чтобы не заметить распашную дверь на задней панели. Обычно это что-то вроде укрепления внешнего интерфейса небезопасного бэкенда, приложения, которое в основном открыто для различных пользователей и т. Д. *

Хорошо и полезно делать общее заявление о безопасности, но оно должно соответствовать требованиям.

2 голосов
/ 04 февраля 2009

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

С другой стороны, если это внутренняя система, где любой злоумышленник, который может получить доступ к SQL-инъекции, может так или иначе причинить ей вред, тогда это действительно не так важно.

Я сам написал код, который уязвим для SQL-инъекций, но единственные, кто имеет такой доступ, все равно являются сотрудниками с SQL-доступом.

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

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

...