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


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

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

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

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!!"); 

}

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

<?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-элемента для ввода формы не делает никакой надежной фильтрации для вас.

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

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

2. Дезинфицируйте / Экранируйте переменные в операторах SQL..

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

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

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

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

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

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

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

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

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

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

во-вторых, могут быть все виды других инъекционных атак, которые вам нужно учитывать: например, пользовательский ввод может содержать 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-страницы.