Должен ли я защищать от 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>

11 ответов


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

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

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

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


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

позвольте мне показать вам, почему, используя консоль разработчика в 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-инъекции.


Как этот вопрос был с тегами sql-injection, вот ответ относительно этого конкретного вида атаки:

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

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

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

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

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


да.

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

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

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. Проверка данных формы.

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

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

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

2. Дезинфицировать / Escape-переменные в операторах SQL..

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

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

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

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

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

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

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

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

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

во-первых, он может принять ваше приложение в состоянии не планировал. Е. Г. если вы хотите, чтобы вычислить средний возраст всех пользователей, а один пользователь дал "aljkdfaqer" за возраст, свой расчет не удастся.

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

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

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

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

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

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

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

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

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

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


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


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


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

SELECT * FROM table WHERE size = ?

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

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

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


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

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


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