@r2eo

В чем смысл Prepared Statements MySQL если внешние данные идут в начале в запрос SET?

Здравствуйте. Изучая mysql наткнулся на кое что не совсем понятное, помогите разобраться! Все говорят что подготовленные запросы повышают безопасность, но не понятно чем?
Если провести эксперимент:
CREATE TABLE child (id INT, name VARCHAR(100), count INT);
-- подготавливаем запрос
PREPARE prQuery FROM 
'SELECT `id` FROM `article` WHERE `id` = ? && `name` = ? && `alias` = ?';
-- связываем данные.
-- Но внешние данные идут как раз сюда и теоретически возможна картина:
SET @varData1 = 4; 
SET @varData2 = 'главная'; DROP TABLE child;--';  /*!!!!!!!*/
SET @varData3 = 'glavnaya'; 
EXECUTE prQuery USING @varData1, @varData2, @varData3;

Если это все выполнить то табличка child удалится, по крайней мере из консоли.
Да в php query одновременно 2 запроса не выполнит, и можно заэкранировать спецсимволы, Тогда какой смысл в Prepared Statements?
  • Вопрос задан
  • 1712 просмотров
Пригласить эксперта
Ответы на вопрос 3
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
Таблица у вас удаляется не во время запроса EXECUTE, а уже в строке SET.
Когда подготовленный запрос выполняется из клиента, то в MySQL передаётся не строка в кавычках, а бинарный блок, содержащий тип, длину и значение, подставляемые в плейсхолдер. таким образом прочитав байты, содержащие тип (строка) и длину (36 байт) сервер просто интерпретирует следующие 36 байт как строку главная'; DROP TABLE child;--. Сам запрос к этому времени уже скомпилирован и превращён в последовательность команд, переменные подставляются без анализа их содержимого, так что этот DROP сервер просто не воспримет как команду.
Ответ написан
Комментировать
Melkij
@Melkij
PostgreSQL DBA
Потому что запросов SET в коде приложения нет. И запросы PREPARE и EXECUTE тоже напрямую не вызываются.
Есть вызовы API, куда сначала в вызов prepare передаётся текст запроса, затем в execute по отдельному бинарному протоколу передаются данные.
Ответ написан
@r2eo Автор вопроса
Спасибо за ответы.
Дело в том что я хотел написать функцию с помошью которой можно былобы нормально получать массив, без $stmt->bind_result работать с которым не очень удобно.
Проблема в том что, чтобы выполнить Execute вначале в запрос нужно передать параметры которые подвержены:
// пришло из гета
	$_GET['id'] = 3;
	$_GET['name'] = "fff'; DROP TABLE child;--";
	$_GET['alias'] = "мммм";	
//подготавливаем запрос	
	$query = "PREPARE prQuery FROM 'SELECT `id` FROM `article` WHERE `id` = ? && `name` = ? && `alias` = ?';";	
// связываем данные 	
	$querySet = "SET @varData1 = $_GET['id']; SET @varData2 = '$_GET['name']'; SET @varData3 = '$_GET['alias']';";

получается:
SET @varData1 = 3; SET @varData2 = 'fff'; DROP TABLE child;--'; SET @varData3 = 'мммм';

// multi_query потому что по одной долбить сервер нет смысла особенно если переменных будет много
// возможно $stmt->bind_param делает тоже самое только с экранированием				
	$mysqli->multi_query($querySet); // и табличке кирдык
	$queryExecute = "EXECUTE prQuery USING @varData1, @varData2, @varData3;";
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы