Какое время использовать real_escape_string? Когда данные поступают в POST или непосредственно перед составлением запроса?

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

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

1) пример экранирования при получении значения:

$test = $mysqli->real_escape_string($_POST['test']); . . . $query=" UPDATE * from test_panel where test='" . $test . "'"; 

2) пример экранирования при составлении запроса:

 $test = $_POST['test']; . . . $query=" UPDATE * from test_panel where test='" . $mysqli->real_escape_string('$test') . "'"; 

Есть ли разница между этими подходами? Какой подход более склонен к инъекциям, и что является самым безопасным способом его предотвращения?

Это довольно интересный вопрос, но ответ не так-то просто.

Какое время использовать real_escape_string? Когда данные поступают в POST или непосредственно перед составлением запроса?

нИ

Позвольте мне объяснить это немного.

Во-первых, давайте разобраться в терминологии. Есть много ошибок в том, как вставлен вопрос.

  1. Давайте поговорим не об экранировании с использованием real_escape_string, а о форматировании . Просто потому, что экранирование имеет очень ограниченное применение – это только часть правил форматирования только одного типа SQL-литералов. В то время как другие типы требуют разных правил форматирования.
  2. Поэтому форматирование, когда данные «прибывают в POST», не может быть и речи – мы просто не можем определить, какое поле входит в какую позицию в запросе, и поэтому мы просто не знаем, какие правила применять.
  3. И последнее, но не менее важное: ни POST, ни любой другой внешний источник не имеют абсолютно никакого отношения к форматированию запросов. После того, как вам нужно вставить строковый литерал в запрос, вы должны отформатировать его в соответствии с синтаксическими правилами SQL, независимо от его источника . То же самое касается чисел и т. Д.

Итак, единственное правильное время, когда мы должны отформатировать наши данные, находится прямо перед составлением запроса.

Однако применение real_escape_string () в коде приложения очень плохое.

  1. Как было сказано выше, экранирования недостаточно для форматирования строки. Форматирование строк включает в себя как экранирование, так и цитирование. Таким образом, независимо от объекта, предназначенного для форматирования строк для SQL-запроса, он всегда должен выполнять обе задачи, а не одну. Оба цитируют и убегают. Потому что эти 2 правила абсолютно бесполезны, если применять одно без другого. Поэтому важно объединить их вместе в одном объекте.
  2. Не забывайте о разных правилах форматирования для разных типов данных. Числа должны быть приведены к этому типу явно, в то время как побег не принесет пользы им.
  3. Ручное экранирование просто глупо. Повторный $mysqli->real_escape_string('$test') делает ваш код раздутым и трудно читаемым. Почему бы не попросить драйвер базы данных делать все форматирование для вас? Итак, вы должны следовать самым современным технологиям – используйте заполнитель для представления данных в запросе. При обработке такого заполнителя драйвер автоматически форматирует данные, находящиеся на своем месте.
    И это будет безопасно и удобно.

Существует 2 метода легкого использования заполнителей (без ручной привязки, что не лучше, чем ручное экранирование с точки зрения удобочитаемости):

  • Используйте PDO, поскольку он позволяет вам просто передать переменную, которая будет использоваться в подготовленном запросе

поэтому код будет

 $db->prepare("SELECT * from test_panel where test=?"); $db->execute(array($_POST['test'])); 

и PDO будет делать все форматирование внутри

  • или изобретать свою собственную упаковку для внедрения заполнителей

как этот

 function paraQuery() { global $mysqli; $args = func_get_args(); $query = array_shift($args); $query = str_replace("%s","'%s'",$query); foreach ($args as $key => $val) { $args[$key] = $mysqli->real_escape_string($val); } $query = vsprintf($query, $args); $result = $mysqli->query($query); if (!$result) { throw new Exception($mysqli->error()." [$query]"); } return $result; } $query = "SELECT * FROM table where a=%s AND b LIKE %s LIMIT %d"; $result = paraQuery($query, $a, "%$b%", $limit); 

или, для вашего текущего запроса:

 $result = paraQuery("SELECT * from test_panel where test=%s", $_POST['test']); 

Посмотрите – он станет коротким, нормальным и безопасным.

Вы должны избегать их как можно позже.

Причина, по которой вы хотите сделать это, – это то, что ваши данные всегда точны. Например, если вы избежите строки сразу в начале, strlen будет не таким же (как неэкранированная версия), что может привести к путанице / ошибкам в некоторых сценариях.


Реальный (imo) ответ на ваш вопрос – это просто забыть об экранировании и использовать prepared statements ,

Не имеет значения, вы избегаете ввода до или в запросе.

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

Если вы не хотите убегать от струн, вы это осознаете 😉

Значения никогда не должны быть экранированы до фактического использования при составлении запроса. Это верно, используете ли вы подготовленный оператор / PDO или используете ли вы real_escape_string для составления запроса в виде строки в формате SQL.

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

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

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

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

Представьте, что вы пытаетесь сделать обратное: предварительно кодировать все значения. Это не реально, так как у вас много много строковых значений, и не все из них должны использоваться в запросах. Где-то у вас, скорее всего, есть переменная, которая используется как вывод на дисплей, так и используемый для запроса. Отображение escape-значения будет неверным. Аналогично сложно (или невозможно) отслеживать, какие переменные предназначены для использования в запросе и которые предназначены для других, не используемых SQL-запросов.

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

Прежде всего, вы должны передать соединение в качестве второго параметра в реальной escape-строке mysqli. Во-вторых, вы также должны использовать подготовленные операторы

http://php.net/manual/en/mysqli.prepare.php