Мы знаем, что для предотвращения проблем с 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 или непосредственно перед составлением запроса?
нИ
Позвольте мне объяснить это немного.
Во-первых, давайте разобраться в терминологии. Есть много ошибок в том, как вставлен вопрос.
Итак, единственное правильное время, когда мы должны отформатировать наши данные, находится прямо перед составлением запроса.
Однако применение real_escape_string () в коде приложения очень плохое.
$mysqli->real_escape_string('$test')
делает ваш код раздутым и трудно читаемым. Почему бы не попросить драйвер базы данных делать все форматирование для вас? Итак, вы должны следовать самым современным технологиям – используйте заполнитель для представления данных в запросе. При обработке такого заполнителя драйвер автоматически форматирует данные, находящиеся на своем месте. Существует 2 метода легкого использования заполнителей (без ручной привязки, что не лучше, чем ручное экранирование с точки зрения удобочитаемости):
поэтому код будет
$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. Во-вторых, вы также должны использовать подготовленные операторы