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

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

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

Я сохраняю $_POST['size'] в сеансе, который затем используется на сайте, чтобы запросить различные базы данных (с запросом mysqli Select), и любая инъекция 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>

Ответ 1

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

$possibleOptions = array('All', 'Large', 'Medium', 'Small');

if(in_array($_POST['size'], $possibleOptions)) {
    // Expected
} else {
    // Not Expected
}

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

Ответ 2

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

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

i've edited one of the values in the dropdown to be a drop table statement

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

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

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

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

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

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

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

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

Ответ 3

Поскольку этот вопрос был помечен , вот ответ относительно этого вида атаки:

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

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

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

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

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

Ответ 4

Да.

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

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

if(in_array($_POST['ddMenu'], $dropDownValues){

    $valueYouUseLaterInPDO = $dropDownValues[array_search("two", $arr)];

} else {

    die("effin h4x0rs! Keep off my LAMP!!"); 

}

Ответ 5

Один из способов защитить пользователей от изменения выпадающих списков с помощью консоли - использовать только целые значения. Затем вы можете проверить, что значение 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 или целое число.

Ответ 6

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

Есть ДВЕ ВЕЩИ:

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.

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

Ответ 7

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

Ответ 8

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

Ответ 9

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

SELECT * FROM table WHERE size = ?

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

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

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

Ответ 10

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

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

Ответ 11

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