Я хотел бы расширить комментарий, который я сделал выше в ответ на сообщение, в котором говорится о том, как использовать оператор 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, а потому, что я хочу, чтобы пользователь мог искать имена, в которые вставлены двойные кавычки.
======
Некоторые выводы:
никогда не принимают ввод данных в свободной форме от пользователей при фильтрации данных - вместо этого используйте элементы управления, которые предварительно проверяют ввод (например, текстовые поля с масками ввода, раскрывающиеся списки, группы параметров) и ограничивают его значениями, которые вам известны действительны.
при приеме данных из текстового поля без ограничений избегайте Application.BuildCriteria, который будет обрабатывать ввод таким образом, чтобы пользователь мог обмануть ваше приложение, возвращая все строки (хотя в этом и заключается эксплойт может сделать).
На практике это означает, что если вы хотите собрать несколько критериев, вам нужно сделать это так, чтобы пользователь мог выбирать только из предварительно выбранных значений. Самый простой способ сделать это с помощью списка с множественным выбором (или пары из них с помощью кнопок ADD >> и << REMOVE между ними). </p>
Конечно, нужно ли вам беспокоиться об этом типе эксплойта SELECT, зависит от важности и уровня конфиденциальности извлекаемых данных, а также от того, что именно возвращается пользователю. При представлении данных в недоступной для редактирования форме (например, в отчете) может возникнуть проблема с риском возврата всех строк нечувствительных данных, в то время как это может быть проблематично, если вы представили их в редактируемой форме, а кто-то изменил данные, которые должны не подлежит редактированию.
Но с нечувствительными данными часто просто не имеет значения, получает ли пользователь слишком много возвращенных данных (за исключением проблем с производительностью, например, перегрузки сервера - но это лучше обрабатывается другими способами).
Итак, мой вынос на все это:
никогда не используйте InputBox () для сбора критериев (этого я уже избегаю).
всегда используйте самые ограничивающие типы контроля для сбора критериев (это уже то, чем я регулярно занимаюсь).
при использовании текстового поля для сбора строковых данных обрабатывайте его как единый критерий независимо от того, что вводит пользователь.
Это означает, что у меня есть некоторые приложения, где пользователь может ввести «Или» = «a» вместе с действительным критерием и вернуть все строки, но в этих приложениях это просто не проблема, поскольку данные не являются конфиденциальными.
Но это хорошее напоминание мне не быть самодовольным. Я думал, что Application.BuildCriteria защитит меня, но теперь понимаю, что служба выражений Jet слишком проста в том, что она принимает в предложении WHERE.
2009/12/08 РЕДАКТИРОВАТЬ: Только что нашел эти ссылки на SQL-инъекции в MS Access. Все они нацелены на веб-инъекцию, поэтому не могут напрямую применяться к обсуждению не-веб-SQL-инъекции (многие из них были бы пустой тратой времени в интерактивном доступе, поскольку у вас уже есть доступ к большей части информации, которая является грубой принудительно (например, информация о файловой системе, путях, исполняемых файлах и т. д.), но многие из методов также будут работать в приложении Access. Кроме того, выполнение из Access открывает множество функций, которые не могут быть запущены из ODBC / OLEDB. Пища для размышлений.