Должен ли я защищать SQL-инъекцию, если я использовал раскрывающийся список?

Я понимаю, что вы НИКОГДА не должны доверять пользовательскому вводу из формы, главным образом из-за возможности SQL-инъекции.

Однако это также относится к форме, в которой единственный вход из выпадающего списка (см. Ниже)?

Я $_POST['size'] на сеансе, который затем используется на сайте, чтобы запросить различные базы данных (с запросом выбора mysqli ), и любая инъекция SQL, безусловно, повредит (возможно, их).

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

 <form action="welcome.php" method="post"> <select name="size"> <option value="All">Select Size</option> <option value="Large">Large</option> <option value="Medium">Medium</option> <option value="Small">Small</option> </select> <input type="submit"> </form> 

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

 $possibleOptions = array('All', 'Large', 'Medium', 'Small'); if(in_array($_POST['size'], $possibleOptions)) { // Expected } else { // Not Expected } 

Затем используйте mysqli_ *, если вы используете версию php> = 5.3.0, которой вы должны быть, чтобы сохранить результат. Если использовать правильно, это поможет с SQL-инъекцией.

Да, вам нужно защититься от этого.

Позвольте мне показать вам, почему, используя консоль разработчика Firefox:

я отредактировал одно из значений в раскрывающемся списке, чтобы быть инструкцией таблицы перетаскивания

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

Просто потому, что вы ограничены тем, какие параметры доступны в раскрывающемся списке , не означает, что вы ограничены данными, которые я могу отправить вашему серверу.

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

 curl --data "size=%27%29%3B%20DROP%20TABLE%20*%3B%20--" http://www.example.com/profile/save 

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

Итак, я повторю:

НИКОГДА не доверяйте вводам пользователей. ВСЕГДА защищай себя.

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

Поскольку этот вопрос был помечен с помощью sql-injection , вот ответ на этот вид атаки:

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

Независимо от любого материала HTML!
Необходимо понимать, что SQL-запросы должны быть отформатированы должным образом независимо от каких-либо внешних факторов, будь то ввод HTML или что-то еще.

Хотя вы можете использовать белый список, предложенный в других ответах для цели проверки ввода, он не должен влиять на любые связанные с SQL действия – они должны оставаться теми же, независимо от того, был ли вы валидированный ввод HTML или нет. Это означает, что вам все равно придется использовать подготовленные инструкции при добавлении каких-либо переменных в запрос.

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

Кроме того, этот вопрос был помечен mysqli . По большей части случайно, я полагаю, но в любом случае, я должен предупредить вас, что raw mysqli не является адекватной заменой для старых функций mysq_ * . Просто потому, что если он используется в старом стиле, он не добавит никакой безопасности вообще. Хотя поддержка подготовленных заявлений является болезненной и сложной, до такой степени, что средний пользователь PHP просто не может их вообще пытаться. Таким образом, если ORM или какая-то библиотека абстракции не является опцией, тогда PDO – ваш единственный выбор.

Да.

Любой может подделать что-либо для значений, которые действительно отправляются –

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

 if(in_array($_POST['ddMenu'], $dropDownValues){ $valueYouUseLaterInPDO = $dropDownValues[array_search("two", $arr)]; } else { die("effin h4x0rs! Keep off my LAMP!!"); } 

Один из способов защитить пользователей от изменения выпадающих списков с помощью консоли – использовать только целые значения. Затем вы можете проверить, что значение POST содержит целое число, и использовать массив, чтобы преобразовать его в текст при необходимости. Например:

 <?php // No, you don't need to specify the numbers in the array but as we're using them I always find having them visually there helpful. $sizes = array(0 => 'All', 1 => 'Large', 2 => 'Medium', 3 => 'Small'); $size = filter_input(INPUT_POST, "size", FILTER_VALIDATE_INT); echo '<select name="size">'; foreach($sizes as $i => $s) { echo '<option value="' . $i . '"' . ($i == $size ? ' selected' : '') . '>' . $s . '</option>'; } echo '</select>'; 

Затем вы можете использовать $size в своем запросе, зная, что он будет содержать только FALSE или целое число.

Другие ответы уже охватывают то, что вам нужно знать. Но, возможно, это помогает прояснить еще кое-что:

Есть ДВА ВЕЩИ, которые вам нужно сделать:

1. Проверьте данные формы.

Как показывает отчет Джонатана Хоббса , выбор элемента html для ввода формы не делает для вас надежной фильтрации.

Проверка обычно выполняется способом, который не изменяет данные, но отображает форму снова, с полями, отмеченными как «Пожалуйста, исправьте это».

В большинстве фреймворков и CMS есть разработчики форм, которые помогут вам в решении этой задачи. И не только это, они также помогают против CSRF (или «XSRF»), что является еще одной формой атаки.

2. Sanitize / Escape переменные в операторах SQL.

.. или пусть подготовленные заявления выполняют эту работу за вас.

Если вы создаете оператор (My) SQL с любыми переменными, предоставленными пользователем или нет, вам нужно убежать и процитировать эти переменные.

Как правило, любая такая переменная, которую вы вставляете в оператор MySQL, должна быть либо строкой, либо то, что PHP может надежно превратить в строку, которую MySQL может переварить. Такие, как, числа.

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

  • В старой школе MySQL + PHP mysql_real_escape_string () выполняет эту работу. Проблема в том, что слишком легко забыть, поэтому вы должны абсолютно использовать подготовленные инструкции или построители запросов.
  • В MySQLi вы можете использовать подготовленные операторы.
  • Большинство фреймворков и CMS предоставляют разработчикам запросов, которые помогут вам в решении этой задачи.

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

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

Что произойдет, если вы опустите один из них?

Если вы не используете проверку формы , но вы дезактивируете свой SQL-вход, вы можете увидеть всевозможные плохие вещи, но вы не увидите SQL-инъекцию! (*)

Во-первых, он может принять ваше приложение в состояние, которое вы не планировали. Например, если вы хотите рассчитать средний возраст всех пользователей, но один пользователь дал «aljkdfaqer» для возраста, ваш расчет не удастся.

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

Там могут быть проблемы с базой данных: например, если поле (столбец таблицы базы данных) ограничено 255 символами, а строка длиннее этого. Или, если поле принимает только числа, и вместо этого вы пытаетесь сохранить нечисловую строку. Но это не «инъекция», а просто «сбой приложения».

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

(*), или это будет что-то действительно экзотическое.

Если вы не избегаете переменных для операторов SQL , но вы проверяли ввод формы, вы все равно можете видеть, что происходит плохая ситуация.

Во-первых, вы рискуете, что, когда вы сохраните данные в базе данных и загрузите их снова, это будут не те же самые данные, «потерянные в переводе».

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

В-третьих, он все равно может вызвать SQL-инъекцию.

Если ваш пользовательский ввод из форм уже отфильтрован / подтвержден, преднамеренная инъекция SQl может стать менее вероятной, если ваш вход сокращен до жестко запрограммированного списка параметров или если он ограничен числами. Но любой свободный ввод текста может использоваться для SQL-инъекции, если вы не избегаете ошибок в операторах SQL.

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

Ваш веб-браузер не «знает», что получает страницу от php, все, что он видит, это html. И уровень http знает даже меньше. Вы должны иметь возможность обрабатывать практически любые входные данные, которые могут пересекать уровень http (к счастью для большинства входных php уже выдаются ошибки). Если вы пытаетесь запретить вредоносным запросам испортить ваш db, вам нужно предположить, что парень на другом конце знает, что он делает, и что он не ограничивается тем, что вы можете видеть в своем браузере при обычных обстоятельствах ( не говоря уже о том, что вы можете играть с инструментами разработчика браузера). Так что да, вам нужно обслуживать любые данные из вашего раскрывающегося списка, но для большинства входных данных вы можете дать ошибку.

Тот факт, что вы ограничили пользователя только использованием значений из определенного раскрывающегося списка, не имеет значения. Технический пользователь может захватить HTTP-запрос, отправленный на ваш сервер, прежде чем он покинет свою сеть, изменит его с помощью такого инструмента, как локальный прокси-сервер, а затем продолжит его на своем пути. Используя измененный запрос, они могут отправлять значения параметров, которые не являются теми, которые вы указали в выпадающем списке. Разработчики должны иметь представление о том, что ограничения клиентов часто бессмысленны, поскольку что-либо на клиенте может быть изменено. Проверка сервера требуется в каждую точку, в которую входят данные клиента. Атакующие полагаются на наивность разработчиков в этом единственном аспекте.

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

 SELECT * FROM table WHERE size = ? 

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

 SELECT * FROM table WHERE size = 'DROP table;' 

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

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

Пример того, что может и произойдет, когда вы доверяете клиенту.

Хакер может полностью обойти браузер, включая проверку формы Javascript, отправив запрос с помощью Telnet. Конечно, он будет смотреть на код вашей html-страницы, чтобы получить имена полей, которые он должен использовать, но с этого момента «все идет» для него. Таким образом, вы должны проверить все значения, представленные на сервере, как если бы они не происходили из вашей html-страницы.