Mysql Защита от SQL-инъекций в PHP и MySQL

Фанат

oncle terrible
Команда форума
"Статья об инъекциях", хехе
Если кто вдруг не видел, Защита от SQL-инъекций в PHP и MySQL

Там фидбек оказался не слишком полезным, и принёс в итоге только одну (но прекрасную) идею.
Возможно, здесь будет продуктивнее?

За вдохновение спасибо, во-первых, Andkorol, а во-вторых - паре авторов с хабра, за их неудачные попытки :)
 

Redjik

Джедай-мастер
Наконец то вы разродились - почти год жду эту статью =)
 

Ragazzo

TDD interested
Читал вчера, конечно не понравилась много спорных моментов, особенно вот этот в примере
То есть, как минимум, со стороны пользователя к нам приходит имя таблицы
не пойму почему это пользователь мне должен присылать имя таблицы, которое должен знать только я разработчик?О_о да я могу впринципе даже подменить ему навзвание полей в ссылках сортировки и когда все прийдет на серв сопоставить в виде ключ-значение, неудачный пример какой-то, для "белого" списка. Ну а так норм) все равно основной посыл всегда в статьях - используй пдо и байнды парметров с препаредами.
 

Фанат

oncle terrible
Команда форума
Ragazzo
Ну, вообще, замечания типа "чо я - дурак что ли" в таких вопросах не слишком продуктивны. Ими можно критиковать любую рекомендацию. К примеру, наш друг Духовность буквально час назад писал то же самое: "если программист сам не заискейпил - то он лох". И никаких тебе байндов с препаредами.

Проблема есть, и должно быть озвучено решение.

кстати, а "имя таблицы" - это ж косяк. должно быть имя поля. Спасибо за поправку. Главное, никто не заметил до сих пор :)

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

Ragazzo

TDD interested
Фанат
Ну, вообще, замечания типа "чо я - дурак что ли"
Ну и где я сделал такое замечание ?. По поводу имени таблицы ок, по поводу полей ну да удобно, не спорю тут(просто в Yii в виджете можно сопоставлять так, очень иногда бывает удобно, чтобы не было в url вида parent_module_id а просто parent :D ну это так для красоты).
 

Фанат

oncle terrible
Команда форума
не пойму почему это пользователь мне должен присылать имя таблицы
вот - это замечание.
точно так же можно писать про любые другие техники: "а зачем мне биндинг, если я руками все прекрасно форматирую"?
 

Фанат

oncle terrible
Команда форума
Redjik
Ну, это, все-таки, не доклад, а статья.
Плюс она очень сильно смещена в сторону ответов людям, которые комментировали предыдущие статьи на Хабре. В частности, приведено развёрнутое объяснение, почему биндинг нужен. А не просто "используй и всё".

Кстати, Ragazzo. Основной посыл - ПОЧЕМУ надо использовать байнды.
А что ещё не понравилось, кроме примера?
 

fixxxer

К.О.
Партнер клуба
Вроде расписано все подробнее некуда - а все равно в комментариях люди продолжают говорить о, цитирую, "данных, защищенных от инъекций". Ох
 

Redjik

Джедай-мастер
Фанат
ее нужно на phpfaq.ru, чтобы новичков просвещать...
 

SiZE

Новичок
Собственно у меня возник вопрос.

1. Мне надо сохранить данные безопасно
2. Данные должны валидироваться только один раз
3. Вернуть соответствующие ошибки для каждого поля пользователю.

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

1. Принимаю в модели набор параметров.
2. Создаю массив <поле> => <значение>, параллельно проверяя на ошибки, ошибки заношу в отдельный массив.
3. После чего передаю массив методу вставки или обновления записи. Массив дополнительно приводится к нужному типу данных перед вставкой (на всякий пожарный).
4. И все это сохраняется.
(Zend_Db для меня очень удобным показался)

Еще плейсхолдеры ввиде "?" вижу не удобными в том случае если параметров много. Надо держать в голове их последовательность, жуть :)

И почему mysql_real_escape_string не защищает значение от инъекций? Про название поля я понял, а вот про значение?
 

Фанат

oncle terrible
Команда форума
SiZE
Спасибо за интересные вопросы.
Хотя я старался ответить именно на них.

Форматирование данных для помещения их в запрос не имеет ни малейшего отношения к валидации данных. Ну то есть вообще никакого. Это абсолютно разные вещи.
Выбрать продукты на борщ - это одно.
Помыть-почистить - совсем другое. На этапе помывки нам уже все равно - морковка это, или дыня. У нас унифицированный механизм закладки любых продуктов, направленный на то, чтобы песок на зубах не скрипел и кожура не плавала.
Вариантов выбора продуктов - миллиарды. Соответствие форматам, предельным значениям и ожидания программиста. Данные, отформатированные для запроса, совсем не обязательно будут валидными (и наоборот):
Имя Д'Артаньян валидно для приложения, но не для запроса.
Число -1 валидно для запроса, но не валидно в качестве значения поля возраст.

Не надо смешивать валидацию на уровне приложения с форматированием на уровне SQL!

Валидация относится ко всему приложению целиком. После валидации данные могут с успехом идти - в базу, в почту, на экран - куда угодно.
Форматирование данных для помещения в SQL запрос относится только к SQL запросу. Отформатированные данные могут идти только в SQL запрос.


Не вижу, как применение плйсхолдеров противоречит приведённой тобой схеме, Если они используются только в п. 4.

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

флоппик

promotor fidei
Команда форума
Партнер клуба
Боле правильная формулировка - mysql_real_escape_string не должна никогда применяться в контексте защиты от каких бы то ни было инъекций.
Это очень, очень плохая и крайне неточная формулировка, как и все формулировки без объяснения происходящего.
 

Фанат

oncle terrible
Команда форума
флоппик
это очень точная формулировка как раз.
то, что она тебе непонятна без дополнительного объяснения - это другой вопрос. но сама по себе она наиболее точная
 

Absinthe

жожо
а все равно в комментариях люди продолжают говорить о, цитирую, "данных, защищенных от инъекций". Ох
А что еще можно ожидать от хабра? :D
Я склонен полагать, что такая фигня присутствует в любом совковом обществе с широкими интересами.

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

Baton

Новичок
Когда читал статью не понял, зачем так сложно:
PHP:
$order   = isset($_GET['order']) ? $_GET['order'] : ''; // просто для полноты кода
$sort    = isset($_GET['sort'])  ? $_GET['sort']  : '';
$allowed = array("name", "price", "qty"); //перечисляем варианты
$key     = array_search($sort,$allowed); // ищем среди них переданный параметр
$orderby = $allowed[$key]; //выбираем найденный (или, за счёт приведения типов - первый) элемент. 
$order   = ($order == 'DESC') ? 'DESC' : 'ASC'; // определяем направление сортировки
$query   = "SELECT * FROM `table` ORDER BY $orderby $order"; //запрос 100% безопасен
Меньше кода и легче для понимания:

PHP:
$order   = $_GET['order'] == 'DESC' ? 'DESC' : 'ASC';
$orderby = in_array( $_GET['sort'], array("name", "price", "qty") ) ? $_GET['sort'] : 'name';
$query   = "SELECT * FROM `table` ORDER BY $orderby $order"; //запрос 100% безопасен
 

Вурдалак

Продвинутый новичок
Во-первых, это нереальный код. Чтобы всё было ясно и никто не смог придраться.
Во-вторых, твой код содержит ошибки, ты не учитываешь Notice.
В-третьих, ты размазываешь логику получения значения поля по умолчанию. При изменении имени поля name или вовсе его удаления, придётся править аж целых два места.
 

Baton

Новичок
Про Notice, соглашусь.
Поле по умолчанию понятнее получать тернарным оператором чем, полагаться на приведение типов.
 
Сверху