Comments 148
Так не лучше?
$sql = "SELECT user FROM userslist WHERE userid='".mysql_real_escape_string($_GET['uid'])."'";
+3
UFO just landed and posted this here
да, еще бы все так писали…
+3
UFO just landed and posted this here
Биндинг к MySQL API практически прямой. На Си почти те же самые функции.
Уже объявлено depricated.
Уже объявлено depricated.
+2
Простите, а где написано что она deprecated? И чем ее предлагается заменять, кроме ORM?
+3
Сорри, не depricated вроде, а not recommended (был уверен в первом). На замену mysqli или PDO_MySQL.
+3
о как, спасибо! Где-то уже натыкался на mysqli, но решил тогда, что это вообще другая СУБД.
-2
Как по мне, так полная ерунда. С таким же успехом можно признать не пригодными еще достаточное количество полезных функций. Составляя запрос нужно думать как человек, который планирует SQL-инъекцию. Сама по себе mysql_query ни хорошая и не плохая — это просто инструмент, а как им пользоваться — личное дело каждого.
+1
UFO just landed and posted this here
Мне вообще непонятно, чем думали авторы PHP, когда добавляли туда mysql_query.
А почему нет? Их вины в небезопасном использовании функции разработчиками помоему нет.
+7
UFO just landed and posted this here
А почему MySQL делали такую функцию? Это как бы язык программирования, а не игрушка для тех кто младше 5 лет.
Во всех книгах по PHP написано, не доверять данным которые пришли из web.
Во всех книгах по PHP написано, не доверять данным которые пришли из web.
+3
Лучше так:
$result = $users->get( $params->uid );
-1
нет, зачем для числа вызывать дорогую функцию mysql_real_escape_string, если приведение типов дешевле?
+18
Только реальное экранирование, для реальных пацанов.
А вообще среди моих знакомых это частая практика — использовать громоздкие решения, там где есть изящные.
А вообще среди моих знакомых это частая практика — использовать громоздкие решения, там где есть изящные.
+3
Да это ж любимая фишка гавнокодеров, они прям мечтают найти одну функцию которая от всех проблем помогает. Они бывает еще strip_tags и htmlentities добавляют для чисел, потому что где вычитали, что это защищает от XSS :)
+5
Плюс к комменту выше: ещё не нужный оверхид с формированием и передачей кавычек (пускай пара байт, но всё же) и приведением строки в число уже в СУБД (тоже мелочь, но всё же). То есть ни одного плюса у этого варианта по сравнению с приведением типа в скрипте нет. Зачем он?
0
Между прочим, приведение типа — не мелочь. У меня как-то раз один запрос работал на два порядка медленнее из-за сравнения числа со строкой, в то время как можно было сравнивать напрямую два числа.
+1
Вероятно потому, что из-за кастования субд не смогла использовать индексы. В то время как во время генерации запроса операция приведения типа ничего не стоит.
+2
О как. Не зря значит привожу тип в php, а не в мускуле. Хотя чисто из эстетических соображений.
0
Ну вообще говоря у mysql были (может сейчас уже исправлено) ситуации, когда по непонятным причинам он в выражениях вроде
WHERE int_field = 'int_value'
приводил к числовому типу не правую, а к строковому левую часть. И получали фуллскан. Сам лично видел такое, да и в интернетах статьи проскакивали о.
WHERE int_field = 'int_value'
приводил к числовому типу не правую, а к строковому левую часть. И получали фуллскан. Сам лично видел такое, да и в интернетах статьи проскакивали о.
+1
Заведомо числовые данные, пришедшие от пользователя, проверяю с помощью RegExp.
Текстовые данные прогоняю через функцию
mysql_real_escape_string
Ведь правильно же?
Текстовые данные прогоняю через функцию
mysql_real_escape_string
Ведь правильно же?
-12
Нет.
+7
Зачем регулярки и почему не использовать intval() или приведение типов?
Да и вообще лично я делаю запросы с использованием placeholder's в любых ЯП где сталкиваюсь с SQL базами данных.
Да и вообще лично я делаю запросы с использованием placeholder's в любых ЯП где сталкиваюсь с SQL базами данных.
+5
placeholder — это очень правильно.
+3
Плейсхолдер плейсхолдеру рознь. Наверное, вы всё же имеете в виду prepared statements.
0
Хммм… ну да, а можно поподробнее о разнице?
0
sprintf — тоже placeholder…
+2
Просто placeholder — это общее понятие, которое просто обозначает место в шаблоне, в которое будет подставлено значение.
Например, в C#:
«Значение» будет подставлено вместо placeholder'а {0}. Но это не значит, что это безопасно с точки зрения SQL. То же самое и в PHP:
%s — плейсхолдер. Но к безопасности такие плейсхолдеры отношения не имеют.
В то же время, одно из предназначений prepared statements — как раз безопасность. Они тоже подставляют значения в плейсхолдеры, но делают это не напрямую (в виде строки), а в виде отдельных параметров-значений, на уровне базы данных.
Например, в C#:
String.Format("SELECT * FROM table WHERE column = {0}", "значение");
«Значение» будет подставлено вместо placeholder'а {0}. Но это не значит, что это безопасно с точки зрения SQL. То же самое и в PHP:
sprintf("SELECT * FROM table WHERE column = %s", "значение");
%s — плейсхолдер. Но к безопасности такие плейсхолдеры отношения не имеют.
В то же время, одно из предназначений prepared statements — как раз безопасность. Они тоже подставляют значения в плейсхолдеры, но делают это не напрямую (в виде строки), а в виде отдельных параметров-значений, на уровне базы данных.
+2
А зачем выполнять запрос, если данные не корректны? intval _всегда_ вернет число, даже если пришла строка.
if( is_int($id) )
{
«select * from users where id=». $id;
}
И не нужноничего экранировать. И лишнего запроса не будет.
if( is_int($id) )
{
«select * from users where id=». $id;
}
И не нужноничего экранировать. И лишнего запроса не будет.
-4
is_int($_GET['id']) — всегда false
+7
Для начала сравните мой кусок со своим, а потом что-то говорите =)
Специально для вас можно использовать is_numeric, подойдет для обоих ситуаций.
Специально для вас можно использовать is_numeric, подойдет для обоих ситуаций.
-4
А мускул поймёт id = 0xff?
echo is_numeric('0xff'); // 1
0
Поймёт, но очень по-своему :-) dev.mysql.com/doc/refman/5.5/en/hexadecimal-literals.html
0
Вообще я вел к тому что интвал всегда возвращает число, даже если строка прийдет, и будет очень неприкольно, если в базе есть данные со значением 0, да и в любом случае не прикольно выполнять запрос, если он в принципе не нужен. Поэтому считаю что нужно сперва проверить число ли пришло, и затем, если да, выполнять уже запрос. Как-то так =) Ато лепят сразу преобразовав, а ошибку человеку увидеть не судьба.
+1
Запрос вроде id=0 выполнится мгновенно, потому что 0 < MIN(id), так что мускул даже пытаться искать по индексу не станет.
Согласен по части «зачем делать лишнюю работу», но с точки зрения программиста — написание этого условия это как раз та самая лишняя работа :-)
Согласен по части «зачем делать лишнюю работу», но с точки зрения программиста — написание этого условия это как раз та самая лишняя работа :-)
+2
стоит уточнить, что id может быть таки и отрицательным, особенно если не auto_increment :)
0
Технически — естественно :-) Практически — приведи пример, когда это имело бы смысл?
0
например когда мы говорим не про первичный ключ и вообще не про индекс.
0
Зависит от ситуации. Лично я на практике в Postresql использую отрицательные значения id для подчеркивания факта наличия «системных» записей. Это как номера TCP портов до 1024 или же uid-ы в линях до 1000-чи.
Просто к основному sequence инкремент возрастающего вверх от нуля есть sequence для системных записей который инкрементится от нуля вниз.
В общем в итоге это не более чем принятое соглашение. Какого соглашение для практического использования приняли, такое и работает.
Просто к основному sequence инкремент возрастающего вверх от нуля есть sequence для системных записей который инкрементится от нуля вниз.
В общем в итоге это не более чем принятое соглашение. Какого соглашение для практического использования приняли, такое и работает.
0
Регуляркой делать.
-3
Прекрасно выбирает строки с айди 19 =)
SELECT *
FROM transactions
WHERE user_ = 0x13
0
Вы ответили на комментарий, где автор рекомендует использовать intval. Написали, что intval вернет всегда число, поэтому надо делать is_int. И откуда тогда в контексте возьмется $id? Я вижу два варианта: $id = $_GET['id'] и $id = intval($_GET['id']). В обоих случаях смысл вашего ответа непонятен.
Функцию is_numeric я знаю. И если вы хотели написать ее вместо is_int, то достаточно было бы ответить, что вы перепутали функции.
Функцию is_numeric я знаю. И если вы хотели написать ее вместо is_int, то достаточно было бы ответить, что вы перепутали функции.
0
Да, я так и понял что написал непонятный коментарий =)
habrahabr.ru/post/142599/#comment_4775262 Тут я обьяснил подробно.
habrahabr.ru/post/142599/#comment_4775262 Тут я обьяснил подробно.
0
>Для защиты от этой шаблонной уязвимости, лучше всего использовать приведение типов.
ОК, а если в get-параметре передаётся не число, а строка?
ОК, а если в get-параметре передаётся не число, а строка?
0
тогда как в примере, только в обрамлении кавычками
+2
Вы получите в приведенном значение 0, что не есть ошибка безопасности.
Я обычно использую следующий подход:
Я обычно использую следующий подход:
$id = (int)$_GET['id'];
+11
А как обезопасить себя, если в get параметре строка и эта строка нужна пример для поиска по базе и не использовать placeholders?
addslashes поможет?
$sql = «SELECT * FROM `table` WHERE title LIKE '%$search%'»;
addslashes поможет?
$sql = «SELECT * FROM `table` WHERE title LIKE '%$search%'»;
0
Как-то так…
$search = base64_encode("%$search%");
$sql = "SELECT * FROM `table` WHERE title LIKE FROM_BASE64('$search')";
-1
А для точного поиска можно использовать md5.
-1
Жесть какая. Оверхед же.
+3
Кто же спорит? Вот человек не может использовать подготовленные выражения, а такой способ позволит пускать строку как есть и при этом не бояться.
-1
mysql_real_escape_string и кавычки чем хуже?
+1
mysql_real_escape_string — изменяет строку.
-3
base64_encode не изменяет что ли?
0
FROM_BASE64 — изменяет обратно.
0
Гм, ну и что? В чём недостаток-то? Помещение строки, пропущенной через mysql_real_escape_string тоже изменяет обратно в недрах MySQL.
+2
Если применять mysql_real_escape_string к INSERT/UPDATE, а потом сделать SELECT, то строка вернётся в первозданном виде.
+1
угу. вот только FROM_BASE64 в mysql появилась только в версии 5.6…
0
Для поиска я использую полнотекстовый поиск, но планирую перейти на Sphinx
0
Гляньте на ElasticSearch
0
Почему не использовать placeholders? Это к тому же наглядно:
$db = new mysqli(...);
$stmt = $db->prepare('update table_name set var1 = ?, var2 =? where var3 = ?');
$stmt->bind_param('sdd', $var1, $var2. $var3);
if ($stmt->execute())
{
…
}
При этом, в теории (ну не нужно мне было это проверять), подготовленный запрос можно использовать несколько раз вроде как без «перекомпиляции». А во вторых можно использовать именованные placeholders, в случае с PDO.
$db = new mysqli(...);
$stmt = $db->prepare('update table_name set var1 = ?, var2 =? where var3 = ?');
$stmt->bind_param('sdd', $var1, $var2. $var3);
if ($stmt->execute())
{
…
}
При этом, в теории (ну не нужно мне было это проверять), подготовленный запрос можно использовать несколько раз вроде как без «перекомпиляции». А во вторых можно использовать именованные placeholders, в случае с PDO.
0
Я имел ввиду, что это не годится для случаев, когда там и должна быть строка.
Например, так:
Впрочем, это я уже придираюсь, наверное.
Например, так:
$username = $_GET['username'];
// обеззараживаем $username
// ...
mysql_query("SELECT ALL FROM blablabla WHERE username = "{$username}");
Впрочем, это я уже придираюсь, наверное.
0
Если в таком запросе должна быть строка, то из-за отсутствия кавычек банально ничего не заработает и даже самый ленивый и неумелый программист пофиксит еще до инъекции.
0
0
Есть такая вещь как унаследованный код. И совершенно случайно работа с БД в нём в отдельный слой не выносится, как правило, хорошо если хоть какие-то слои есть.
+2
Я о том только, что если ты даешь советы, — напиши основное.
0
ИМХО если мы тыкаемся в legacy код и видим в нем грязные mysql_ с невнятным поведением при некорректных аргументах — мы просто берем и заменяем эти вызовы на *ABSTR_DB_LAYER* (мы же новый код не по тем же принципам пишем, верно? у нас абстракции, модульность, программирование на уровне интерфейсов и вообще лучшие практики курят в сторонке).
0
Не всегда это просто.
0
Да. Не всегда.
У меня недавно был проект без архитектуры на инклудах, где магическая переменная магической погоняет. Это настолько классический случай лапши и плохого дизайна, что все сурсы можно запросто выкинуть на govnocode и получить +300 их рейтига.
Тогда я честно сказал заказчику, что если он хочет от меня что-то новое или правки старого функционала, это значит что мы будем удалять(выжигать железом) старый код и внедрять новый.
Понимаю, что не всегда дают деньги и время на это, но если нет времени на рефакторинг, значит с менеджментом что-то не так.
У меня недавно был проект без архитектуры на инклудах, где магическая переменная магической погоняет. Это настолько классический случай лапши и плохого дизайна, что все сурсы можно запросто выкинуть на govnocode и получить +300 их рейтига.
Тогда я честно сказал заказчику, что если он хочет от меня что-то новое или правки старого функционала, это значит что мы будем удалять(выжигать железом) старый код и внедрять новый.
Понимаю, что не всегда дают деньги и время на это, но если нет времени на рефакторинг, значит с менеджментом что-то не так.
0
У «лапши» зачастую есть одно важное свойство — она работает худо-бедно и объяснить заказчику (или партнёру в моем случае), что нужно месяц минимум просто приводить в порядок код без всякого изменения функциональности очень сложно.
0
Простите, а подход «не использовать вообще конкатенацию запросов, только передачу параметров» в PHP невозможен?
0
одно непонятно — зачем пускать к базе непроверенные запросы-то? :) Одного if жалко?
Переменная дешевле чем два intval, а if дешевле чем холостой запрос к базе.
$g_uid = intval($_GET['uid']);
if ($g_uid == $_GET['uid']) {
$sql = "SELECT user FROM userslist WHERE userid=".$g_uid;
}
Переменная дешевле чем два intval, а if дешевле чем холостой запрос к базе.
-8
Почему два intval'а то? Один. И у вас один. Только лишние if и переменная. Тем более параметров зачастую не один, а больше. Соответственно, вы что, будете в if делать проверку 5-10 переменных?
+4
А почему бы и нет, если это касается безопасности.
-2
Если превратить код в помойку ненужными проверками, то безопаность от этого только проиграет. Нет ничего страшного в выборке «WHERE id = 0», которая случается только в случае крайне редких махинаций. Да и если постоянно идут запроса «WHERE id = N» (N > 0 ), то «WHERE id = 0» явно не повесит сервер.
+2
>Если превратить код в помойку ненужными проверками
Это зависит от уровня восприятия. Если для вас if и пустые запросы в порядке вещей, то для меня это не приемлемо.
Это зависит от уровня восприятия. Если для вас if и пустые запросы в порядке вещей, то для меня это не приемлемо.
0
Первый вариант:
Второй вариант:
Я обычно использую второй, потому что разницы по сути нет, а вот писать каждый день сотни лишних строк я не хочу (времени жалко).
if (!isset($_GET['id'])) Core::forward404();
$topicId = intval($_GET['id']);
if ($topicId < 1) Core::forward404();
$db = Core::getDatabase();
$topic = $db->selectRow('SELECT * FROM topics WHERE topic_id = ?d', $topicId);
if (!$topic) Core::forward404();
...
Второй вариант:
$topicId = isset($_GET['id']) ? intval($_GET['id']) : 0;
$db = Core::getDatabase();
$topic = $db->selectRow('SELECT * FROM topics WHERE topic_id = ?d', $topicId);
if (!$topic) Core::forward404();
...
Я обычно использую второй, потому что разницы по сути нет, а вот писать каждый день сотни лишних строк я не хочу (времени жалко).
+3
а так
$topicId = intval($_GET['id']);
if ($topicId) {
$db = Core::getDatabase();
$topic = $db->selectRow('SELECT * FROM topics WHERE topic_id = ?d', $topicId);
if (!$topic) Core::forward404();
}
0
Запрос, в котором не выполняется условие
intval($_GET['uid']) == $_GET['uid']
, может быть вполне корректен семантически. Да и даже если нет, проще сделать холостой запрос, чем «пачкать» код проверками, если число холостых пренебрежимо мало.0
Можно несколько проще
if (is_numeric($_GET['uid']))
...
+1
Вы ПХП-то знаете вообще? Суньте в _GET например такую строку: «9 AND UNION SELECT 1 FROM DUAL». Она чудесно пройдёт проверку.
+3
К строке
К числу
$sql = "SELECT id FROM userslist WHERE username='" . mysql_real_escape_string($_GET['username']) . "'";
К числу
$sql = "SELECT user FROM userslist WHERE userid='" . intval($_GET['uid']) . "'";
+4
Я обычно так пишу. Почти))
Не знаю, есть ли какой-то дополнительный смысл в наличии/отсутствии кавычек вокруг имен таблиц и столбцов, но мне так проще читать код
$sql = "SELECT `user` FROM `userslist` WHERE `userid`='" . intval($_GET['uid']) . "'";
Не знаю, есть ли какой-то дополнительный смысл в наличии/отсутствии кавычек вокруг имен таблиц и столбцов, но мне так проще читать код
0
В кавычках вокруг intval смысла нет, если userid число.
+4
Я хотел бы услышать комментарий про другие кавычки)
В любом случае, предпочитаю ставить кавычки везде, в том числе вокруг intval
В любом случае, предпочитаю ставить кавычки везде, в том числе вокруг intval
0
Без их использования есть риск потерять совместимость с будущими версиями (My)SQL. Также иногда можно получить ошибку при попытке использовать зарезервированное слово и приходится оборачивать (если увидел ошибку). Потому правильным считаю ставить в запросах для единообразия, но зачастую лень, если специального требования нет. Если же речь идёт о чём-то универсальном, где имя таблицы/поля заранее неизвестно (например задаётся пользователем), то нужно ставить однозначно.
0
Комментарий на эту тему: FYI: escaping table/field names is only required if you're using reserved words. Dumping everything into backticks just makes the query that much harder to read.
0
Кстати, лучше всё-таки „(int)“, в ПХП вызов функции — дорогая операция.
+3
Я использую библиотеку DbSimple от Котерова. На сколько мне известно, она используется и на этом движке, на котом хабр.
+3
Аналогично. Использую допиленный DbSimple. Плюс писал свою версию с нуля для MSSQL, так как очень не хватало привычных методов при работе с этой СУБД.
0
Ссылка: dklab.ru/lib/DbSimple/ (много примеров)
$ids = array(1, 101, 303);
$db->select('SELECT name FROM tbl WHERE id IN (?a)', $ids);
...
$name = $_GET['name'];
$db->selectRow('SELECT * FROM users WHERE name = ?', $name);
...
$row = array('name' => 'Hint', 'age' => 25);
$db->query('INSERT INTO users SET ?a', $row);
+1
Выглядит красиво, но как производится сама проверка?
0
В комментарии я привел далеко не все плюшки.
Все подстановки с "?" экранируются как строки. Все элементы массивов при подстановке "?a" экранируются как строки, а ключи массивов при UPDATE и INSERT как идентификаторы (`name`).
Для подстановок с "?d" выполняется intval:
Все подстановки с "?" экранируются как строки. Все элементы массивов при подстановке "?a" экранируются как строки, а ключи массивов при UPDATE и INSERT как идентификаторы (`name`).
Для подстановок с "?d" выполняется intval:
$topic = $db->selectRow('SELECT * FROM topics WHERE id = ?d', $_GET['id']);
+1
А разв Хабр на php? Я почему-то думал, что он на asp.
-4
Обычно использую:
+ ессно автоэкранирование кавычек в строках
".select .. from ... where strcmp(field,'".$mustBeString."')=0 or id=".(int)$mustBeInt.";"
+ ессно автоэкранирование кавычек в строках
+1
Мой сайт хакали именно через такую SQL инъекцию. Век живи, век учись.
+1
Если заведомо число передается, всегда делают some sql query where id=".(int)$value."… а вообще стараюсь чтобы всегда только числа передавались, а уж если строка, то кучу перепроверок + экранирование.
Тут народ intval предлагает, чем то лучше или хуже (а то вдруг 6 лет зря (int) пихаю)?
Тут народ intval предлагает, чем то лучше или хуже (а то вдруг 6 лет зря (int) пихаю)?
+1
Только параметризованные запросы. Никаких конкатенаций. В PHP есть параметризованные запросы? Простите давно не писал на нем, не помню.
0
А под фреимворки регулярки не составляли?)
Когда нарочно обходят использование preapared statements конкатенацией.
Когда нарочно обходят использование preapared statements конкатенацией.
+1
Не составлял, сложно и муторно. Есть средства статического анализа кода, они позволяют выполнять эту работу более комплексно и не привязаны к конкретным конструкциями.
0
Средства статистического анализа кода, написанного на PHP-фреймворках?
Не подскажите какой-нибудь? Буду благодарен.
Статистический анализ кода так или иначе привязан к конкретным конструкциям.
Не подскажите какой-нибудь? Буду благодарен.
Статистический анализ кода так или иначе привязан к конкретным конструкциям.
0
у нас своя разработка статического анализатора. Статический анализ привязан скорее уже не к конструкциям, а к структуре кода, скорее всего вы про это и говорили. Поэтому такие вещи как RIPS не справляются с ООП. Но если знать, что хочется найти, то, скажем, выполнить задачу «поиск всех функций где аргумент попадает в SQL запрос без фильтрации» выполнить можно быстро и качественно.
+1
А, понятно, у вас свой анализатор. Просто думал какой-то инструмент используете с уже собранными регулярками.
Действительно, теперь про анализ мы друг друга поняли.
С последним, да, у меня у меня именно так: наткнулся на уязвимую конструкцию и грепаешь весь код на подобные, действительно, быстро и качественно.
Действительно, теперь про анализ мы друг друга поняли.
С последним, да, у меня у меня именно так: наткнулся на уязвимую конструкцию и грепаешь весь код на подобные, действительно, быстро и качественно.
0
Ага, тоже так делал, пока не устал эти регулярки писать. Очень много получается веб-приложений и все такие разные, что пришлось изобретать какую-то утилиту под свои нужды. В целом, посмотрите на TXL (http://www.txl.ca/ www.txl.ca/examples/Grammars/PHP/README.txt)
0
только экранирование, только хардкор!
0
Sign up to leave a comment.
Самый частый шаблон SQL инъекций в РНР — бесполезное экранирование символов