Pull to refresh

Comments 160

Проверка почерка — это не фильтрация данных. Фильтрация данных относится к подстановкам в запрос (placeholders), а не к целому запросу. Не будете же вы брать запрос целиком из ввода пользователя.

Функции mysql_* уже давно deprecated в PHP.

Ошибка «Warning: mysql_fetch_array() expects parameter 1 to be resource, boolean given» — не индикация того, что инъекция работает (хотя косвенно инъекция является причиной). Эта ошибка происходит из-за того, что mysql_query завершился неудачно и вернул false, а кое-кто поленился проверить в коде этот результат.

К тому же статья содержит большое количество грамматических ошибок. В общем, мне не понравилось.
Эта ошибка происходит из-за того, что mysql_query завершился неудачно и вернул false, а кое-кто поленился проверить в коде этот результат.

Согласен, т.к. тестируется на скриптах написанных «На коленке» и на локалхосте, поэтому при любой ошибке, даже синтаксиса, выводится данное уведомление. На «Боевых» скриптах, будет нужный вывод ошибок.
При чем тут локалхост и боевые скрипты? У вас написано как-то так:

$r = mysql_query($q);
while($row = mysql_fetch_row($r)) {
  //...
}

А должно быть так:

$r = mysql_query($q);
if ($r) {
  while($row = mysql_fetch_row($r)) {
    //...
  }
} else {
  //обработка ошибки
}

Как обрабатывать ошибку, зависит от окружения, но проверка должна быть всегда.
$user = mysql_real_escape_string($_GET['user']);

Вот за такие советы нужно по рукам бить, вы уж простите. PDO на это есть и prepared statements, привыкайте, что ли к цивилизованным методам.
Вы меня тоже извиняйте, но я просто дал совет опять же новичкам. В своих проектах я всегда использую Active records, и практически не задумываюсь.
Так это прекрасно, что используете, но новичков-то зачем плохому учить? Может, подредактируете статью?
Объясните, в чем пагубность mysql_real_escape_string() и вообще mysql_*?
Я лично такое вот делаю

$mdb->mes( $g_id ) или $mdb->query( «SELECT * FROM… WHERE id = '».((int)$g_id)."'" );

Оно по сути тот же mysql_* в мин обертке. Никогда не задумывался, что можно лучше. А я так понимаю можно? Но чем оно лучше?
**
$mdb->mes( $g_id )

$mdb->query( "SELECT * FROM xxx WHERE id = '".((int)$g_id).";'" );
prepared statements как минимум быстрее работают при прочих равных (эффективней задействуется механизм кеширования) и защищены от разного рода незапланированных внедрений в запрос. В итоге меньше кода (не надо никаких монстров экранирования и конкатенаций), всё чище и логичней, работа идёт быстрей и не будет очень неприятных сюрпризов в будущем (где там у какого поля тип поменялся — перепиши все запросы, где спешили и забыли заэкранировать — слили базу паролей).
Быстрей нам надо, очень надо.
Попробуем то есть.
Хотя последовательных запросов не бывает вообще.
Если надо что-то оно в LEFT JOIN обычно, и редко в INNER JOIN
пагубность mysql_real_escape_string() в том, что люди не понимают ее смысла.
большая часть пользователей похапе искренне полагает, что эта функция служит не для экранирования спецсимволов в строках, а для защиты от инъекций.

пагубность mysql_ заключается в двух вещах.
Первая чисто теоретическая — РНР-тим забил на эту либу и не хочет ее поддерживать. проблем с этим никаких нет, но теоретически ее могут в какой-то момент объявить deprecated.
Вторая заключается в том, что в коде не должно быть вызовов голого API. А должны быть — как совершенно правильно сделано у вас — вызовы функции- надстройки.

Единственно что, вместо ручной обработки передаваемых данных, лучше использовать автоматическую, с помощью плейсхолдеров:

$mdb->query( «SELECT * FROM table WHERE id =? AND name=?", $id, $name);

Это одновременно и упростит, и обезопасит код

а про быстроту там ниже ерунду написали
Чем сложнее инструменты используются для объяснения, тем больше объяснять нужно. Хотя, с другой стороны, тема требует наличия специальных навыков.
Цивилизованные методы хороши на больших проектах с продуманной архитектурой, где запрос в БД скрыт за толстым слоем ООП и генерируется в автоматическом режиме…
Для небольших скриптов достаточно простой фильтрации входящих данных по типу (в большинстве случаев надо просто привести к int, ибо в таких скриптах 80% запросов обычно идёт тупо по primary key) или же mysql_real_escape_string…
Архаичные костыли вроде mysql_real_escape_string плохи вне зависимости от контекста. Тут даже выигрыша в объеме кода нет по сравнению с PDO, не понимаю, какой может быть смысл их использовать, кроме того, что кому-то лень выучить что-то другое.
Выигрыш по потребляемым ресурсам (скорости, памяти), т. к. mysql_* является по сути просто биндингами к libmysql, а mysqli/pdo создают ненужный во многих случаях объектный слой?
Вот не приведу сейчас источник, но мне mysqli_* сватали именно ради большей производительности оного по сравнению с mysql_*. Что творится с производительностью в PDO — увы не в курсе, но PDO рекомендуют уже как серебряную пулю — мол под все базы всё стандартизировано (насколько это возможно) и соответственно «простая миграция, универсальные решения». Если разобраться, то я, например, так или иначе всё равно пользуюсь объектными обёртками. Думаю встроенная в систему «обёртка» должна быть лучше вылизана, чем отдельный код и в реализации на C — более продуктивна.
а в чем проблема с mysql_real_escape_string? В нём есть какие-то известные уязвимости?
единственная проблема mysql_real_escape_string() в том, что люди не понимают ее смысла.
большая часть пользователей похапе искренне полагает, что эта функция служит не для экранирования спецсимволов в строках, а для защиты от инъекций.

ну и еще есть проблемы при неправильном использовании её с некоторыми экзотическими кодировками.
а можно про кодировке подробнее? в мане сказано, что ресурс подключения передаётся туда как раз для того, чтобы заэкранировать исходя из конкретного подключения
Ну так ресурсу же это тоже надо сказать :)
А это делается только функцией mysq_set_charset(), про которую большинство разработчиков не подозревает. Так что абсолютное большинство пользуется этой функцией совершенно без малейшей пользы :)

И мы бы давно сидели по уши в инъекциях, если бы эта уязвимость не работала только для ооочень экзотических кодировок.
можно пример с инъекцией для экзотической кодировки?
google://alshanetsky addslashes — должно найтись
> А это делается только функцией mysq_set_charset(), про которую большинство разработчиков не подозревает

Почему-то мне кажется, что оно и без этой ф-ции работает верно.
Т.к. у меня в коде есть запрос SET NAMES, но нет mysql_set_charset.

При этом, строки в KOI8-R и UTF-8 экранируются правильно (по-разному).
Если использовать mysql_escape_string (без передачи ресурса параметром), то она «сбоит» — портит строки при экранировании, если кодировка UTF-8.

> alshanetsky addslashes
Нашёл это:

In some cases the escape process can be
abused to execute exploits!
Escaping Shortfall Cont.
// invalid multi-byte sequence with ASCII equiv. of ¿’
$str = 0xBF. 0x27;
// after addslashes() or even mysql_real_escape_string()
// the value becomes [ 0xBF 0x5C ] 0x27
// a valid multi-byte sequence of 縗 followed by ‘.
SQL Injection is once again possible!!!
Native escaping function is only vulnerable if charset
is changed manually via “SET CHARACTER SET” query.

Как я понял проблема заключается в том, что ф-ции экранирования не совсем корректно работают с мультибайтовыми строками. Т.е. например для того же UTF-8 может проявиться уязвимость.
«При этом, строки в KOI8-R и UTF-8 экранируются по-разному» — да ладно! можно пример?

«Если использовать mysql_escape_string (без передачи ресурса параметром), то она «сбоит» — портит строки при экранировании, если кодировка UTF-8.» — Это тоже полная ерунда.
Вы бы хоть попробовали сначала, прежде чем писать.
Умозаключения — это всегда хорошо. Но их обязательно проверять надо :)

При этом пример по ссылке в гугле показывает, что функция как раз сбоит С ПЕРЕДАЧЕЙ параметра. Вы нашли эту статью?
ilia.ws/archives/103-mysql_real_escape_string-versus-Prepared-Statements.html
Попробуйте выполнить из нее примеры. Это совсем не так сложно. Зато сразу снимет кучу вопросов и неверных догадок :)
Приведите хоть один адекватный аргумент против такой строки?
UFO just landed and posted this here
Потому что подобный стиль может привести к тому, что рано или поздно забудешь заискэйпить. Я поэтому стараюсь использовать шаблонизаторы — как-то раз забыл написать htmlspecialchars и было очень больно.
Это не агрумент, так как эта функция происходит из mysql основ, именно он эскейпит в данном случае данные в отличии от mysql_escape так что аргумент вообще не в тему. Эабыл — не аргумент! Я не забываю делать правильные вещи и mysql_real_escape_string одна из вещей которые я не стоит забывать!
Вы не забываете, а уверены что ваш напарник не забудет? Или стажер?
А вы уверены что не забудите биндить в PDO? Так можно про все сказать.
Если не забиндить — работать не будет. А если не заэскейпить — внешне не заметно, что что-то не так. До одного прекрасного момента (в идеале — до аудита кода, но в жизни обычно бывает очень не идеально).
На самом деле и забывать-то не обязательно.
Достаточно забыть (или не иметь возможности) выполнить вторую часть заклинания — поставить по краям переменной кавычки — без которой карета, увы, тут же превращается в тыкву…

Главная проблема этой строчки — непонимание её смысла.
причина в том, что эта строка ни с какой стороны не является защитой от инъекций, при этом большая часть пользователей понимает её именно так.
> Приведите хоть один адекватный аргумент против такой строки?

Вырежут скоро mysql_* функции из PHP
проблема в контексте.
сама по себе строка нормальная, в ней ничего ужасного нет.

но если она преподносится в контексте защиты от инъекций, то это, конечно, ужас.

плюс, если если функция посреди кода, а не внутри библиотечного метода — это тоже караул.

Если что, эта функция вызывает встроенные в драйвер mysql защиты от инъекций, а не пхп-шные методы, поэтому никакого ужаса нет, а очень даже большая польза.
Если что, эта функция не имеет никакого отношения к защите от инъекций :)
Если внимательно присмотреться к ее названию, то слова «защита» или «инъекция» почему-то в нем не встречаются.

Поэтому даже если не «забывать» её писать, что обсуждалось в ветке выше, инъекции после её использования могут быть — только в путь.
$name = mysql_real_escape_string($name);
'SELECT * FROM `users` WHERE `name` = "{$name}";';

Можете мне привести пример инъекции на этот код, если функция не имеет никакой защиты?
Могу, но речь не о них. Будем считать, что нет.
Речь не о каком-то частном примере, а о понимании.
Рекомендую, все-таки, почитать что-нибудь, чтобы не писать ерунды про «встроенные в драйвер mysql защиты от инъекций» :)

Часть защиты от инъекции — экранирование данных. R чему здесь mysql_real_escape_string подумайте сами, до PDO мои скрипты прекрасно жили без инъекций, это так, к слову.
О, молодец. Уже начинаешь потихоньку соображать, что сама по себе эта функция ничего ни от кого не защищает — Уже не «встроенные защиты», а «часть». :)

Теперь осталось совсем чуть чуть: подумать, для чего на самом деле нужна эта функция, и почему она должна применяться ВНЕ зависимости от каких-либо инъекций.
И какие бывают случаи, когда она применяться не должна.

То, что твои скрипты «прекрасно жили» говорит либо о том, что ты применял не одну только эту функцию для защиты от инъекций, либо о том, они живут не так прекрасно, как ты воображаешь :)

А ПДО, кстати, тоже совсем недостаточна для защиты от инъекций. В более-менее сложных запросах.
Может поделитесь опытом что нужно еще для защиты от sql инъекций?
habrahabr.ru/post/148151/#comment_5018969

Но опять это «ещё» :)
Я настаиваю на том, что функция искейпинга не должна применяться в контексте защиты от инъекций! Если это происходит, то инъекция будет гарантирована, рано или поздно.

Почему? Вы делаете раз за разом категоричные заявления, но не приедите аргументов. Я понимаю про устаревшесть, пдо и все такое, но объясните мне, почему недостаточно эскейпить все входные данные от пользователя и каким образом при правильно настроенных кодировках эта функция может стать причиной дыры в безопасности

Потому что эскейпинг не предназначен для защиты от инъекций. Точка.


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


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


А "эскейпить все входные данные от пользователя" это уже совсем дно. Когда-то в ПХП была такая функция, "волшебные кавычки" называлась. Но уже 10 лет назад её с ужасом и стыдом из языка выпилили. Опять же, надо дать себе труд задуматься — что с ней было не так. Помимо того, что эскейпинг сам по себе не имеет отношения к инъекциям, тут у нас еще одна черная дыра глупости — "входные данные от пользователя". Если спросить среднего похапешника, какие данные входят от пользователя, аакие нет, волосы встанут дыбом. Во всех местах. Так что если доверить этому похапешнику решать, какие данные надо защищать и когда, то проще пароль от базы данных сразу написать на главной странице сайта.

Простите, я давно не занимался серьезным серверным программированием, а когда и занимался — пользовал плейсхолеры. так что уже смутно помню что и к чему. Но «оно не предназначено и точка» — совершенно не убеждает. Можно, пожалуйста, поменьше эмоций и чуть больше фактов? Ну вот к примеру mysql_real_escape_string:

Эта функция должна всегда (за несколькими исключениями) использоваться для того, чтобы обезопасить данные, вставляемые в запрос перед отправкой его в MySQL.
То есть вы противоречите официальной документации PHP.

пс. простите за некропостинг, я только недавно заметил, что год топика — 2012-й

По этой ссылке написано, что Данное расширение устарело, начиная с версии PHP 5.5.0, и удалено в PHP 7.0.0.
В актуальной документации этой ереси нет.

Что "есть"? По этой ссылке можно увидеть корректные формулировки, бреда про "обезопасить данные" там нет.

Там написано "можно использовать в SQL выражениях". Может все-таки как-то проаргументируете свои мысли? Ну вот, к примеру, такой неприятный пример, как можно сделать в нем sql-инъекцию?


$in = $_GET['city'];
$escaped = mysqli_real_escape_string($link, $in);
$query = "INSERT into myCity (Name) VALUES ('$escaped')";
mysqli_query($link, $query)

Не уходим от темы. Вопрос ко мне был, "можно ли использовать эту функцию для защиты от инъекций". По ссылке выше не написано, что можно. Вообще ни одного слова про инъекцию. Еще вопросы будут?

Но и не написано, что нельзя. Просто написано, что данные можно вставлять в запрос, нигде не написано ни о какой опасности. Это как раз вы уходите от темы. Я вам задал вполне конкретный вопрос — почему недостаточно заэскейпить? Вы меня высмеяли. Привел пример с mysqli_real_escape_string и спросил у вас на примере, теперь вы голову в песок — «я не я и сообщения не моя».

Давайте я задам вам вопрос иначе. «Почему нельзя использовать mysqli_real_escape_string в качестве защиты от sql-инъекций?» Только пожалуйста, без эмоций, сухие факты, если есть. Если нету — так и скажите.
Но и не написано, что нельзя.

Дружище, это уже совсем за гранью добра и зла и формальной логики. В описании функций strlen, htmlspecialchars, empty, intval, urlencode, sort, header тоже не написано, что их нельзя применять для защиты от инъекций. Cогласно вашей логике получается что можно?


Просто написано, что данные можно вставлять в запрос,

Там нету слова "данные".


Почему нельзя использовать mysqli_real_escape_string в качестве защиты от sql-инъекций?

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

Нельзя потому что нельзя. Окей. Давайте я еще раз переформулирую.
Если я, как последний глупец, буду использовать mysqli_real_escape_string для защиты от инъекций — какие проблемы я могу отхватить? Допустим, мой прадедушка пару лет назад сделал сайт про рыбалку, он там использовал эту функцию для защиты от инъекций и я вот хочу оценить риски и понять — нужно ли ему срочно переводить сайт на PDO и плейсхолдеры или можно оставить mysqli_real_escape_string и продолжить делать сайт про охоту? Он у меня просто не очень прогрессивный и ему сложно даются новые технологии. Так расскажите мне риски, пожалуйста, я хочу их оценить
Нельзя потому что нельзя.

Я ничего такого не писал. Не надо перевирать мои слова.


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


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

Это ведь просто строки, там нет никакой магии и никакой магии не нужно, чтобы сдержать инъекции. Вы просто мне говорите, что real_escape_string — неправильно, что считать, что она защищает — ошибка, но не приводите аргументов, почему. Вы просто ожидаете, что я приму это на веру, но почему? Если это — ошибка, если приводит к каким-то проблемам, то будьте любезны — объясните, к каким проблемам может привести эта ошибка. В чем, сообственно, ошибка заключается? И как правильно? Вот, к примеру, википедия утверждает, что экранирование спецсимволов — вполне себе «Защита от атак типа внедрение SQL-кода»

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


Если в каком-то отдельно взятом случае эта функция случайно помогла, это не значит, что ее предназначение именно в защите от инъекций.


Это ведь просто строки

Не только строки

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

И по какой причине ее недостаточно?

По той причине, что она, в качестве побочного эффекта, защищает от инъекций только строковые литералы. Для всех остальных элементов запроса она бесполезна, и ее использование приведет к инъекции. Именно по этой причине её категорически нельзя использовать для защиты.

Для всех остальных элементов запроса
Например, каких?

Для любых. Если можешь назвать хоть один, то он подойдет. Напиши на бумажке SQL запрос, и выбери любую его часть, которая не строковый литерал. Вот для ее защиты real_escape_string и будет бесполезна на 146%

Я не могу. Назовите, пожалуйста, пару примеров.

Мда.


SELECT * FROM news ORDER BY $field

если нам требуется сортировка по выбираемому пользователем полю, то real_escape_string не защитит его от слова "никак".

Ну допустим. Можете привести пример инъекции?

Зададим тебе это в качестве домашнего задания :)

Ты забавный мальчик :)


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

Я откуда знаю, почему ты снова поднял топик полуторамесячной давности.

Это твоя главная проблема.

Это вообще не моя проблема)

И именно поэтому ты поднял топик многолетней давности, ага :)
Логика это явно твоя сильная сторона.

Поднял топик я:
1. По ошибке (увы, не заметил, что он стар)
2. Потому что не знал (и так и не узнал) ответ на вопрос

Мои причины вполне логичны и я их могу назвать. А зачем вы подняли устаревший топик, если до сих пор не можете дать ответ на простой вопрос?

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


Чтобы понять ответ на вопрос, надо заранее знать половину ответа. Для тебя же "строки", "инъекция" и "эскейпинг" — это абстрактные понятия, не имеющие физического смысла. Когда-то в далеком детстве ты прочитал сказку, что "инъекция" — это злой Кащей Бессмертный, а "эскейпинг" — это молодцеватый Илья-муромец, который разит супостата прямо в темечко. На таком уровне я действительно не готов объяснять, извини.


Попробуй самостоятельно найти хотя бы один пример инъекции и разобраться как она работает. Понять чем отличается строковый литерал от идентификатора в SQL. Чем конкретно занимается пресловутый искейпинг, и зачем. После того как разговор перейдет для тебя из мифологической в практическую плоскость, можно будет продолжить.


Если же тебе лень это делать то придется принимать на веру, точно также как ты когда-то принял на веру бред про "обезопасить данные".

На самом деле я тебе ответил

Я повторю, возможно переформулировав, вопрос. Максимально кратко, если не доходит:
Приведи пример инъекции.

Все остальное твое самолюбование не имеет никакого смысла. Спекуляции на тему «может быть, а может сам догадаешься» работают только в детском саду.

Увы, ты не читаешь то, что я так талантливо и образно формулирую. Это пустая трата времени :(

А, так это ты для меня писал? Я думал, что это был просто самовосхваляющий монолог.

Я что-то подобное и подозревал. Данное предубеждение мешает тебе воспринимать информацию. То есть ты сам же себе мешаешь.

Данное предубеждение мешает тебе воспринимать информацию.
Предубеждение про самолюбование? Информацию о твоем самомнении я воспринял прекрасно.
если нам требуется сортировка по выбираемому пользователем полю

Кстати, я тут нагуглил, что PDO::prepare вообще не позволяет подставить поле, так что все-равно необходимо будет думать об этом независимо от того, используешь ли ты их:
You cannot search with a prepared statement
This fails:
  "SELECT * FROM users WHERE :search=:email"
This succeeds:
  "SELECT * FROM users WHERE $search=:email"

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


Все верно, PDO::prepare с идентификаторами не работает. Но главное здесь в том что prepare сразу не даст так сделать, а escape_string молча проглотит и ты заложишь первоклассную инъекцию в свой код. Теперь ясно?

Теперь ясно?
Нет, не ясно. Если человеку необходимо будет так вставить название поля — ему все-равно придется как-то это сделать (я, правда, не представляю, кто может в качестве названия поля напрямую вставлять ввод пользователя, но это уже детали).

Кстати, на счет фокусов. Я тут прочитал еще раз топик и увидел, что вы начинаете путаться в своих показаниях. Вот тут вы говорите, что она защищает строковые литералы:
По той причине, что она, в качестве побочного эффекта, защищает от инъекций только строковые литералы.

А вот тут, что не защищает:
taliban
$name = mysql_real_escape_string($name);
'SELECT * FROM `users` WHERE `name` = "{$name}";';
Можете мне привести пример инъекции на этот код, если функция не имеет никакой защиты?

FanatPHP
Могу, но речь не о них.


Хотя я, кажется, начинаю понимать, что вы имели ввиду. Что иногда можно вставить в запрос даже заэскейпленные данные и они не защищат от инъекции. Ну типа такого:

// example.com?name=1 OR 1=1

$name = mysql_real_escape_string($_GET['name']);
query("SELECT * FROM `users` WHERE `name` = $name;");


Вы это имели ввиду?

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

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

Ради бога, ты можешь воображать все что тебе угодно :)
Твоя убежденность в собственной правоте умиляет не меньше, чем твоя убежденность в том, что кому-то интересно твое мнение :)

Да-да, иди уже, громко хлопнув дверью.

Мне тебя немного жаль, конечно, но почему я должен при этом хлопать дверью, не очень понятно. Впрочем, тема дверей мне уже не настолько интересна.
Будут еще вопросы по базам данных — обращайся, я всегда помогу!

И снова я вынужден повторять в который раз, real_escape_string не имеет никакого отношения к инъекциям и никогда не должен использоваться для защиты от них.

Статья понравилась. Пусть есть ошибки, пусть примеры не очень корректны. Я так понял что цель — объяснить что к чему В ОБЩЕМ новичкам. Вот мне, человеку озабоченному вопросами безопасности своих сайтов, эта статья очень полезна. Я, конечно, наслышан что такое SQL-иньекции, как с ними можно бороться, но конкретных примеров инъекций не разбирал. А тут все показали на пальцах. Соответственно, мне как НЕ специалисту в вопросах безопастности для общего развития стало это очень полезно. Ну и для практического применения тоже. Надеюсь, что цикл статей продолжится и я научусь еще более эффективно защищать свои программы.
И еще хотелось бы чтобы автор в следующих публикациях уделил время разбору методов борьбы с такими вот штуками. Он конечно говорит что нужно использовать фильтрацию и т.д. и т.п. и про все это в нете можно почитать, про фильтрацию данных и про инъекции. Но мне бы хотелось услышать эти вещи именно от этого автора. Чтобы подробнее были разобраны методы фильтрации.
Не нужно никакой фильтрации.
Нужно всегда соблюдать всего два правила:
— данные пподставляем в запрос только через плейсхолдеры.
— идентификаторы и ключевые слова подставляем только из белого списка, прописанного в нашем коде.
Всё. Больше ничего не нужно, никакой фильтрации.

Можно лишь добавить, что плейсхолдеры могут использоваться либо родные — от БД, либо самодельные.
В последнем случае наш парсер должен знать тип подставляемых данных, и корректно их отформатировать.
Статья вообще неочем. Это обжовывалось 300 раз.

Вы бы лучше объяснили незнающим, почему в PHP 10 + «15 apples» даст в результате 25, а 10 + «apples 15» — 10 и т.п…
Поверьте, Вам бы это стоило немного поковырять документацию + исходники, а статья была бы очень даже интересной, на мой взгляд.
Повторюсь Статья «рассчитана на тех, кто не сталкивался с подобным, но хотел бы научиться». Если Вы это знаете — то хорошо.
Статья в целом неплохая. А вот комментарий вообще «неочем».
Mirrage, а вы новичок в этом деле? Полагаю что нет. Прочтите внимательнее, в заголовке написано "… для начинающих". Поэтому, мне кажется, чтобы объективно рассуждать о чем статья или не о чем, надо быть для начала новичком!
Я вот новичок, и мне статья очень понравилась!
Вы хотите сказать, что разрабатывали что-то не зная про SQL инъекции?
Вы понимаете чем отличается новичок от не новичка?
А он родился уже знающим, так на этом уровне и остался видимо :)
Расскажу по секрету: существует большое количество разработчиков, которые не имеют понятия об sql инъекциях, о принципах проектирования, юзабилити, тестировании, проверки на неправильные параметры и как вообще правильно писать код.
Знаю. И знаю как с ними бороться. Но конкретных примеров не разбирал. А тут мне на пальцах показали как это выглядит изнутри.
Например, я знаю какие символы недопустими в передаваемых параметрах, но как применить эти недопустимые символы в «плохих» целях я не знал. Разве что совсем простые примеры.
Тут мне показали как это можно использовать.
И так понял что в дальнейшем автор планирует показать более сложные примеры.

P.S. например для такого использования union я не додумался. А автор мне показал. Теперь буду знать врага в лицо.
Уважаемый AlexanderPHP, а вам не стыдно?

Мне одному кажется что это сжатый и немного измененый пересказ уже существующей статьи датированной 2010 годом? Причем очень много чего в этих статьях схожего.
rdot.org/forum/showthread.php?t=124

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

К примеру пытаться обнаруживать иньекции только по наличию ошибок — бред. В ~80% случаях вывод ошибок отключен, и приходится ориентироваться на поведение самого приложения.
А, все понятно с автором.
InSys, спасибо, будет что еще почитать. Всё писалось из головы.
Из головы ли? Пробежался глазами. Даже примеры вообщем то совпадают.

Не верю
(с) Станиславский.
Синтаксис — один. Это тоже самое, что Hello world, в разных учебниках.
Вам совсем необязательно что-то кому-то доказывать. Просто у людей сложилось мнение о Вас лично.
Придраться можно к чему либо. Правильно Вы сказали — что нет смысла оправдываться. Самому себе, мне нет смысла врать.
В Яндексе все такие клевые?
Не принимайте близко к сердцу, но если у Вас не хватает ума ответить «да» или «нет», на вопрос, подразумевающий данный ответ, то с Вами не о чем разговаривать.
>если у Вас не хватает ума ответить «да» или «нет», на вопрос, подразумевающий данный ответ, то с Вами не о чем разговаривать.
«Вы уже перестали избивать свою мать?»
Правильный ответ «нет», не перестал, т.к. не начинал это делать)
С точки зрения формальной логики — да, правильный. С точки зрения бытовой — не очень)
Оригинал:
Так как мы не можем повлиять на их количество в первом запросе, то нам нужно подобрать их количество во втором к первому.

Ваша:
Т.к. мы не можем повлиять на их количество в первом запросе, то нам нужно подобрать их количество во втором, чтобы оно было равно первому.


Пример со сто рублями передран и немного переделан. Используется таже таблица news… Продолжать?

Откровенно говоря, оригинал данной статьи я когда то очень долго держал у себя как личную «библию», и очень часто обращался к ней за помощью, именно по ней я научился некоторым фишкам. И тут приходите вы, и пытаетесь выдать чужое за свое…
и пытаетесь выдать чужое за свое…

Уважаемый, я ничего чужого, за своё не пытаюсь выдать. Более ничего Вам доказывать не буду. Не вижу смысла мне врать.
Ну конечно, уже что-то доказывать смысла нет. Странный вы человек. Возьмите, да добавьте в статью ссылки на используемые материалы. Не стройте из себя гения который сам всему научился и все знает, вот и вся проблема.
Мне кажется вам стоило больше уделить защите от SQL инъекций. То что вы описали не всегда применимо. Да и фильтрация очень редко закрывает уязвимость
Хочу дополнить, что способ защиты указан не верный, хотя конечно он верный, если у вас в $_GET['id'] всегда числовые значение. Но вот что делать, если там могут быть и строки? Правильно, в ход идет escape. Поэтому фильтрация должна быть правильная, т.е. уместная на каждом участке кода. А то бывает встречаются такие ситуации:

$_GET['id'] — всегда число, а фильтрация escape для запроса вида
SELECT * FROM news WHERE id=1

Таким образом нам даже и кавычка не нужна для sql-injecton. Достаточно просто положить -1 UNION SELECT 1 в $_GET['id']
Да и по поводу определение колонок методом group by написано не точно.

>>Если при GROUP BY 4 нет ошибки, а при GROUP BY 6 — ошибка, Значит кол-во полей равно 5

Может быть 4 поля, ибо мы не знаем как оно реагирует на group by 6
И еще… Стоило указать какая СУБД используется, ибо не во всех СУБД все примеры будут рабочие. к примеру с LOADFILE
Соискатель как-то присылал ссылку на свою работу в качестве портфолио. С совершенно чудной SQL-injection в форме логина. По крайней мере пользователь ' or 1 # считался администратором и пароль при этом не спрашивался. А вообще это даже грустно.
Встречал забавный случай, на сайте одного из факультетов моего ВУЗа, сейчас именно это уже закрыто: был JS скрипт, который делал все запросы очень весело, т.е. страница новостей передавала в него, что хочет новости, скрипт собирал SQL запрос, и посылал на сервер в виде server/sql.php?q=SELECT * FROM news… Инъекции? Зачем инъекции?
Чтобы «Взломщик» умер от смеха, и не стал ломать сайт.
Это называется server side javascript :)
Я тоже подобное использовал. А там тоже в sql.php проводился лексический анализ запроса и проверка его на опасность?
Нет, там было что-то такое:
mysql_query($_GET($q))

Поэтому случай так сильно и запомнился.
Извините, давно на php ничего не писал:
$_GET['q']
Тогда, да, было бы смешно, если бы не было так грустно.
ВНИМАНИЕ! Перед и после него обязательно должны стоять пробелы.

Пробел должен стоять только после —
Отлично, файл у нас записался. Таким образом, Мы можем залить мини-шелл:
sqlinj/index2.php?user=-1' UNION SELECT 1,'<?php eval($_GET[1]) ?>',3,4,5 INTO OUTFILE '1.php' --%20

Такой INTO OUTFILE ничего не даст, так как файл запишется в datadir, не доступный из веба.
Палишься :D

более того если запрос как в статье

SELECT * FROM news WHERE id=1

то коммент вообще не нужен
Странно, что никто ещё не вставил картинку про Робина-брось-таблицу :)
Очень интересно, а зачем SQL-базе команды чтения и записи файлов? Это как раз уязвимое звено. А скрипт, по необходимости, может сам с файлами пообщаться
Уязвимое место — люди, пишущие сей код. А какова функциональность уже другой вопрос. В mssql вообще можно из под sa выполнять команды на машине, и что? :)
Уязвимое место — люди, пишущие сей код

Грамотно и емко сказанно. Отчаянно плюсую!
UFO just landed and posted this here
Ну знаете что, давайте выбросим SELinux, AppArmor, песочницу хрома, из-за которой он считается самым безопасным браузером (несмотря на уязвимости)
Лучше уберите про способы защиты, а то как-то…

Ни слова про привилегии на таблицы/базы? Если у пользовательского скрипта задача только читать, и только из двух таблиц, то ему достаточно соединятся с базой под максимально ограниченными привилениями.

Да и про фильтрацию как-то невнятно… фильтровать желательно не только входящие, но и исходящие данные, причем не только по типу, но и по размеру с диапазоном. Забирать сырое значение из _GET небезопасно по умолчанию, это чревато не только иньекциями. Отдавать шаблонизатору результат неизвестно какого формата тоже опрометчиво.
фильтровать желательно не только входящие, но и исходящие данные, причем не только по типу, но и по размеру с диапазоном.

можете пояснить более подробно?

Отдавать шаблонизатору результат неизвестно какого формата тоже опрометчиво.

На то он и шаблонизатор, чтобы всё что нужно заэкранировать. Шаблонизатор обязан получать сырые данные, если мы хотим сделать разделение логики представления данных и логики получения данных.
Автор, докажи, что не украл статью с ачата или рдота — напиши продолжение.
Блин, хотел ссылку вставить
UFO just landed and posted this here
с src тут дружбу не водят=(
тогда sql-injection.jpg
тьфу, плохая карма даёт о себе знать.
UFO just landed and posted this here
PDO и ORM не панацея. И с использованием pdo можно наделать подобных дыр, если нет понимания как работают sql-инъекции.
Sign up to leave a comment.

Articles