Самый частый шаблон SQL инъекций в РНР — бесполезное экранирование символов

По роду своей деятельности, мне приходится выполнять аудиты безопасности исходного кода веб-приложений.
Много веб-приложений и много кода…

В этой статье я хотел бы поделиться одной простой (очень простой) истиной и статистикой, которые вывел и многократно проверил в течении трех последний лет просмотра тонн РНР кода.

Не секрет, что уязвимости внедрения операторов СУБД (SQL injections) являются самыми распространенными из всех серверных уязвимостей веб-приложений. Есть платформы и фреймворки, где такие вещи практически полностью исключены, например ORM'ом и прочим. Но статистика упорно говорит нам об абсолютном преобладании на просторах Интернета веб-приложений с простыми конкатенированными SQL запросами. Кроме того, есть случаи, где ORM вообще применим быть не может. Например, когда от пользовательских данных должны зависеть не только параметры выражений, но и сама логика запроса на уровне операторов.

Итак, начнем.

Бесполезное экранирование символов

Найдено в 83% РНР веб-приложений, уязвимых к SQL-инъекциям

Применение функции экранирования символов, таких как
mysql_escape_string
mysql_real_escape_string
addslashes
без обрамления кавычками. Чаще всего проявляется в числовых параметрах (всевозможные *_id).

Пример

$sql = "SELECT user FROM userslist WHERE userid=".mysql_real_escape_string($_GET['uid']);

На вид, это безопасный код, но только на вид. Сюда закрался самый частый в моей практике шаблон SQL-инъекций в РНР. Для проведения атаки на эту уязвимость от злоумышленника требуется просто не использовать символы " ' \x00 \r \n \x1a в векторе атаки.
Например:
/index.php?uid=-777 UNION SELECT password FROM userlist

Поиск в коде

Осложнен семантикой языка. Для простого поиска можно использовать egrep:
egrep -Rin "(select|update|insert|delete|replace).*(from|set|into).*(mysql_escape_string|mysql_real_escape_string|addslashes)" . | grep -v "[\"']['\"]"

Логика поискового выражения такая — найти все строки, в которых слева от функций фильтрации нет последовательности символов кавычек ('', "", "', '"). Метод, разумеется, далеко не 100%, но требовать от регулярного выражения выполнить семантический анализ невозможно.
Для удобства вывода информации, можно подсветить функцию цветом в консоли:
egrep -Rin "(select|update|insert|delete|replace).*(from|set|into).*(mysql_escape_string|mysql_real_escape_string|addslashes)" . | grep -v "[\"']['\"]" | egrep --color "(mysql_escape_string|mysql_real_escape_string|addslashes)"

Для защиты от этой шаблонной уязвимости, лучше всего использовать приведение типов.
Это всегда быстрее работает и надежнее чем всевозможные фильтрации и экранирования.
Для примера выше, патч может быть таким:
$sql = "SELECT user FROM userslist WHERE userid=".intval($_GET['uid']);


На этом короткий очерк окончен. Призываю всех веб-разработчиков попробовать гренуть свои исходники на предмет таких конструкций. А еще лучше, расширить приведенный поисковый скрипт для людей.
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 148

    +3
    Так не лучше?
    $sql = "SELECT user FROM userslist WHERE userid='".mysql_real_escape_string($_GET['uid'])."'";
    
    • UFO just landed and posted this here
        +3
        да, еще бы все так писали…
          –8
          В проектах серьёзнее курсовой работы это должно быть не предпочтительным, а единственно допустимым вариантом.

          Мне вообще непонятно, чем думали авторы PHP, когда добавляли туда mysql_query. И чем думают сейчас, продолжая поддержку этой дырени в безопасности во всех новых версиях интерпретатора.
            +2
            Биндинг к MySQL API практически прямой. На Си почти те же самые функции.

            Уже объявлено depricated.
              +3
              Простите, а где написано что она deprecated? И чем ее предлагается заменять, кроме ORM?
                +3
                Сорри, не depricated вроде, а not recommended (был уверен в первом). На замену mysqli или PDO_MySQL.
                  –2
                  о как, спасибо! Где-то уже натыкался на mysqli, но решил тогда, что это вообще другая СУБД.
                    +1
                    Как по мне, так полная ерунда. С таким же успехом можно признать не пригодными еще достаточное количество полезных функций. Составляя запрос нужно думать как человек, который планирует SQL-инъекцию. Сама по себе mysql_query ни хорошая и не плохая — это просто инструмент, а как им пользоваться — личное дело каждого.
                      +1
                      а аргумент что mysql медленее mysqli для вас тоже не существенен?
                        0
                        Это другой вопрос. Но в плане безопасности я особого изъяна не вижу. Естественно, что mysqi приоритетней.
                  0
                  Библиотека для работы с СУБД — это как раз то место, где правильная реализация передачи в запрос значений аргументов решает проблему с SQL-инъекциями. Красиво, эффективно, навсегда.

                  По-моему, стоило об этом думать при реализации и развитии языка программирования. А не о том, как сделано на C.
                  +7
                  Мне вообще непонятно, чем думали авторы PHP, когда добавляли туда mysql_query.

                  А почему нет? Их вины в небезопасном использовании функции разработчиками помоему нет.
                    +42
                    Ну как сказать…

                      +1
                      Весело, программистов уже сравнивают с маленькими детьми. Думать головой уже не модно, нужно побольше магических функций которые делают всё за тебя.
                        +2
                        Когда этот «программист» валит все свои проблемы на фреймворк, то вполне нормально сравнивать его с ребенком, который пробует все подряд без вникания в подробности зачем это сделано именно так.
                          0
                          В вопросах безопасности всех людей по умолчанию нужно считать маленькими детьми.
                        +3
                        А почему MySQL делали такую функцию? Это как бы язык программирования, а не игрушка для тех кто младше 5 лет.
                        Во всех книгах по PHP написано, не доверять данным которые пришли из web.
                          0
                          не доверять данным которые пришли из web.

                          Вот-вот :)
                      –1
                      Лучше так:
                      $result = $users->get( $params->uid );
                      
                      • UFO just landed and posted this here
                      +18
                      нет, зачем для числа вызывать дорогую функцию mysql_real_escape_string, если приведение типов дешевле?
                        +3
                        Только реальное экранирование, для реальных пацанов.
                        А вообще среди моих знакомых это частая практика — использовать громоздкие решения, там где есть изящные.
                          +5
                          Да это ж любимая фишка гавнокодеров, они прям мечтают найти одну функцию которая от всех проблем помогает. Они бывает еще strip_tags и htmlentities добавляют для чисел, потому что где вычитали, что это защищает от XSS :)
                          0
                          Плюс к комменту выше: ещё не нужный оверхид с формированием и передачей кавычек (пускай пара байт, но всё же) и приведением строки в число уже в СУБД (тоже мелочь, но всё же). То есть ни одного плюса у этого варианта по сравнению с приведением типа в скрипте нет. Зачем он?
                            +1
                            Между прочим, приведение типа — не мелочь. У меня как-то раз один запрос работал на два порядка медленнее из-за сравнения числа со строкой, в то время как можно было сравнивать напрямую два числа.
                              +2
                              Вероятно потому, что из-за кастования субд не смогла использовать индексы. В то время как во время генерации запроса операция приведения типа ничего не стоит.
                                +2
                                Да, думаю, именно из-за невозможности использования индексов.
                                0
                                О как. Не зря значит привожу тип в php, а не в мускуле. Хотя чисто из эстетических соображений.
                                  +1
                                  Ну вообще говоря у mysql были (может сейчас уже исправлено) ситуации, когда по непонятным причинам он в выражениях вроде

                                  WHERE int_field = 'int_value'

                                  приводил к числовому типу не правую, а к строковому левую часть. И получали фуллскан. Сам лично видел такое, да и в интернетах статьи проскакивали о.
                                    0
                                    Никогда так не писал, потому не встречал, наверное. Но в чужом коде попадалось, да — иногда исправлял, иногда нет. Теперь всегда буду.
                                      0
                                      профайлинг — наше все.
                            –12
                            Заведомо числовые данные, пришедшие от пользователя, проверяю с помощью RegExp.

                            Текстовые данные прогоняю через функцию
                            mysql_real_escape_string

                            Ведь правильно же?
                              +7
                              Нет.
                                +5
                                Зачем регулярки и почему не использовать intval() или приведение типов?

                                Да и вообще лично я делаю запросы с использованием placeholder's в любых ЯП где сталкиваюсь с SQL базами данных.
                                  +3
                                  placeholder — это очень правильно.
                                    0
                                    Плейсхолдер плейсхолдеру рознь. Наверное, вы всё же имеете в виду prepared statements.
                                      0
                                      Хммм… ну да, а можно поподробнее о разнице?
                                        +2
                                        sprintf — тоже placeholder…
                                          +3
                                          Ну, $sql = sprintf("SELECT * FROM users WHERE id = %d", $_GET['id']); не самый худший вариант экранирования для чисел, по-моему.
                                            +1
                                            только медленный, если сравнивать с «SELECT * FROM `users` WHERE `id` = ».(int)$_GET['id']
                                          +2
                                          Просто placeholder — это общее понятие, которое просто обозначает место в шаблоне, в которое будет подставлено значение.

                                          Например, в C#:
                                          String.Format("SELECT * FROM table WHERE column = {0}", "значение");

                                          «Значение» будет подставлено вместо placeholder'а {0}. Но это не значит, что это безопасно с точки зрения SQL. То же самое и в PHP:
                                          sprintf("SELECT * FROM table WHERE column = %s", "значение");

                                          %s — плейсхолдер. Но к безопасности такие плейсхолдеры отношения не имеют.

                                          В то же время, одно из предназначений prepared statements — как раз безопасность. Они тоже подставляют значения в плейсхолдеры, но делают это не напрямую (в виде строки), а в виде отдельных параметров-значений, на уровне базы данных.
                                            0
                                            А %d тоже не имеет?
                                              +1
                                              %d приводит значение к целочисленному типу, причём делает это нестрого и втихую. Но да, %d поможет избежать инъекций.
                                      –4
                                      А зачем выполнять запрос, если данные не корректны? intval _всегда_ вернет число, даже если пришла строка.
                                      if( is_int($id) )
                                      {
                                      «select * from users where id=». $id;
                                      }
                                      И не нужноничего экранировать. И лишнего запроса не будет.
                                        +7
                                        is_int($_GET['id']) — всегда false
                                          –4
                                          Для начала сравните мой кусок со своим, а потом что-то говорите =)
                                          Специально для вас можно использовать is_numeric, подойдет для обоих ситуаций.
                                            0
                                            А мускул поймёт id = 0xff?
                                            echo is_numeric('0xff'); // 1
                                            
                                              0
                                              Поймёт, но очень по-своему :-) dev.mysql.com/doc/refman/5.5/en/hexadecimal-literals.html
                                                –1
                                                Не смертельно :-)
                                                +1
                                                Вообще я вел к тому что интвал всегда возвращает число, даже если строка прийдет, и будет очень неприкольно, если в базе есть данные со значением 0, да и в любом случае не прикольно выполнять запрос, если он в принципе не нужен. Поэтому считаю что нужно сперва проверить число ли пришло, и затем, если да, выполнять уже запрос. Как-то так =) Ато лепят сразу преобразовав, а ошибку человеку увидеть не судьба.
                                                  +2
                                                  Запрос вроде id=0 выполнится мгновенно, потому что 0 < MIN(id), так что мускул даже пытаться искать по индексу не станет.

                                                  Согласен по части «зачем делать лишнюю работу», но с точки зрения программиста — написание этого условия это как раз та самая лишняя работа :-)
                                                    0
                                                    стоит уточнить, что id может быть таки и отрицательным, особенно если не auto_increment :)
                                                      0
                                                      Технически — естественно :-) Практически — приведи пример, когда это имело бы смысл?
                                                        0
                                                        например когда мы говорим не про первичный ключ и вообще не про индекс.
                                                          0
                                                          Ну в данном случае мы говорим про первичный ключ id ;-) И я комментировал очень специфичную ситуацию
                                                            0
                                                            в целом да, выше скорее всего шла речь про первичный ключ, иначе не знаю, что еще может означать id в таблице users и выборка по нему, ну кроме случаев лапше- и индусо- кода ;)
                                                          0
                                                          Зависит от ситуации. Лично я на практике в Postresql использую отрицательные значения id для подчеркивания факта наличия «системных» записей. Это как номера TCP портов до 1024 или же uid-ы в линях до 1000-чи.

                                                          Просто к основному sequence инкремент возрастающего вверх от нуля есть sequence для системных записей который инкрементится от нуля вниз.

                                                          В общем в итоге это не более чем принятое соглашение. Какого соглашение для практического использования приняли, такое и работает.
                                                    –3
                                                    Регуляркой делать.
                                                      0
                                                      Прекрасно выбирает строки с айди 19 =)
                                                      SELECT *
                                                      FROM transactions
                                                      WHERE user_ = 0x13
                                                      
                                                      0
                                                      Вы ответили на комментарий, где автор рекомендует использовать intval. Написали, что intval вернет всегда число, поэтому надо делать is_int. И откуда тогда в контексте возьмется $id? Я вижу два варианта: $id = $_GET['id'] и $id = intval($_GET['id']). В обоих случаях смысл вашего ответа непонятен.

                                                      Функцию is_numeric я знаю. И если вы хотели написать ее вместо is_int, то достаточно было бы ответить, что вы перепутали функции.
                                            0
                                            >Для защиты от этой шаблонной уязвимости, лучше всего использовать приведение типов.

                                            ОК, а если в get-параметре передаётся не число, а строка?
                                              +2
                                              тогда как в примере, только в обрамлении кавычками
                                                +11
                                                Вы получите в приведенном значение 0, что не есть ошибка безопасности.
                                                Я обычно использую следующий подход:
                                                $id = (int)$_GET['id'];
                                                
                                                  0
                                                  А как обезопасить себя, если в get параметре строка и эта строка нужна пример для поиска по базе и не использовать placeholders?
                                                  addslashes поможет?

                                                  $sql = «SELECT * FROM `table` WHERE title LIKE '%$search%'»;
                                                    –1
                                                    Как-то так…
                                                    $search = base64_encode("%$search%");
                                                    $sql = "SELECT * FROM `table` WHERE title LIKE FROM_BASE64('$search')";
                                                    
                                                      –1
                                                      А для точного поиска можно использовать md5.
                                                        +3
                                                        Жесть какая. Оверхед же.
                                                          –1
                                                          Кто же спорит? Вот человек не может использовать подготовленные выражения, а такой способ позволит пускать строку как есть и при этом не бояться.
                                                            +1
                                                            mysql_real_escape_string и кавычки чем хуже?
                                                              –3
                                                              mysql_real_escape_string — изменяет строку.
                                                                0
                                                                base64_encode не изменяет что ли?
                                                                  0
                                                                  FROM_BASE64 — изменяет обратно.
                                                                    +2
                                                                    Гм, ну и что? В чём недостаток-то? Помещение строки, пропущенной через mysql_real_escape_string тоже изменяет обратно в недрах MySQL.
                                                                      –1
                                                                      Признаю свою ошибку. Не прав. Это, возможно, от того, что я не пользуюсь этой функцией.: )
                                                                      +1
                                                                      Если применять mysql_real_escape_string к INSERT/UPDATE, а потом сделать SELECT, то строка вернётся в первозданном виде.
                                                            0
                                                            угу. вот только FROM_BASE64 в mysql появилась только в версии 5.6…
                                                              –1
                                                              Ох как меня пропёрло. Действительно. наверное, плохая погода на меня подействовала так…
                                                            0
                                                            Для поиска я использую полнотекстовый поиск, но планирую перейти на Sphinx
                                                              0
                                                              Гляньте на ElasticSearch
                                                                0
                                                                Я пользуюсь MariaDB, там есть некоторая интеграция Sphinx в движок, правда я не разбирался насколько удобная интеграция.
                                                              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.
                                                              0
                                                              Я имел ввиду, что это не годится для случаев, когда там и должна быть строка.

                                                              Например, так:

                                                              $username = $_GET['username'];
                                                              // обеззараживаем $username
                                                              // ...
                                                              mysql_query("SELECT ALL FROM blablabla WHERE username = "{$username}");
                                                              


                                                              Впрочем, это я уже придираюсь, наверное.
                                                              0
                                                              Если в таком запросе должна быть строка, то из-за отсутствия кавычек банально ничего не заработает и даже самый ленивый и неумелый программист пофиксит еще до инъекции.
                                                              0
                                                              Не пользуйтесь вообще функциями mysql_.
                                                              Читайте документацию:
                                                              www.php.net/manual/en/intro.mysql.php
                                                                +2
                                                                Есть такая вещь как унаследованный код. И совершенно случайно работа с БД в нём в отдельный слой не выносится, как правило, хорошо если хоть какие-то слои есть.
                                                                  0
                                                                  Я о том только, что если ты даешь советы, — напиши основное.
                                                                    0
                                                                    ИМХО если мы тыкаемся в legacy код и видим в нем грязные mysql_ с невнятным поведением при некорректных аргументах — мы просто берем и заменяем эти вызовы на *ABSTR_DB_LAYER* (мы же новый код не по тем же принципам пишем, верно? у нас абстракции, модульность, программирование на уровне интерфейсов и вообще лучшие практики курят в сторонке).
                                                                      0
                                                                      Не всегда это просто.
                                                                        0
                                                                        Да. Не всегда.

                                                                        У меня недавно был проект без архитектуры на инклудах, где магическая переменная магической погоняет. Это настолько классический случай лапши и плохого дизайна, что все сурсы можно запросто выкинуть на govnocode и получить +300 их рейтига.
                                                                        Тогда я честно сказал заказчику, что если он хочет от меня что-то новое или правки старого функционала, это значит что мы будем удалять(выжигать железом) старый код и внедрять новый.

                                                                        Понимаю, что не всегда дают деньги и время на это, но если нет времени на рефакторинг, значит с менеджментом что-то не так.
                                                                          0
                                                                          У «лапши» зачастую есть одно важное свойство — она работает худо-бедно и объяснить заказчику (или партнёру в моем случае), что нужно месяц минимум просто приводить в порядок код без всякого изменения функциональности очень сложно.
                                                                            0
                                                                            Тут было чуть попроще — я наладил обмен между ERP и e-commerce системой и с новыми данными половина системы не завелась. Из-за хардкода id, названий, неявных параметров.
                                                                            Так что тут либо отказываться от обмена, либо переписывать компоненты. Заказчик в тему вьехал и дал добро.
                                                                  0
                                                                  Простите, а подход «не использовать вообще конкатенацию запросов, только передачу параметров» в PHP невозможен?
                                                                    0
                                                                    С расширением mysql — нет.
                                                                      0
                                                                      С расширением mysql и небольшой оберткой — да.
                                                                        0
                                                                        Это пишут в манах и учебниках «PHP за 1 час»?
                                                                          0
                                                                          По-вашему нет ничего среднего между prepared statements и ORM?
                                                                            0
                                                                            Есть. Но никто об этом не говорит/не пишет, хорошо если про prepared statements напишут.
                                                                        0
                                                                        Ээээ… ну тогда понятно, почему это такая больная тема.
                                                                          0
                                                                          зато уже давно есть mysqli и я не понимаю почему кто-то еще до сих пор может использовать mysql_*, кроме как на давно устаревших проектах.
                                                                        –8
                                                                        одно непонятно — зачем пускать к базе непроверенные запросы-то? :) Одного if жалко?

                                                                        $g_uid = intval($_GET['uid']);
                                                                        if ($g_uid == $_GET['uid']) {
                                                                        $sql = "SELECT user FROM userslist WHERE userid=".$g_uid;
                                                                        }


                                                                        Переменная дешевле чем два intval, а if дешевле чем холостой запрос к базе.
                                                                          +4
                                                                          Почему два intval'а то? Один. И у вас один. Только лишние if и переменная. Тем более параметров зачастую не один, а больше. Соответственно, вы что, будете в if делать проверку 5-10 переменных?
                                                                            –2
                                                                            А почему бы и нет, если это касается безопасности.
                                                                              +2
                                                                              Если превратить код в помойку ненужными проверками, то безопаность от этого только проиграет. Нет ничего страшного в выборке «WHERE id = 0», которая случается только в случае крайне редких махинаций. Да и если постоянно идут запроса «WHERE id = N» (N > 0 ), то «WHERE id = 0» явно не повесит сервер.
                                                                                0
                                                                                >Если превратить код в помойку ненужными проверками

                                                                                Это зависит от уровня восприятия. Если для вас if и пустые запросы в порядке вещей, то для меня это не приемлемо.
                                                                                  +3
                                                                                  Первый вариант:
                                                                                  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();
                                                                                  ...
                                                                                  


                                                                                  Я обычно использую второй, потому что разницы по сути нет, а вот писать каждый день сотни лишних строк я не хочу (времени жалко).
                                                                                    0
                                                                                    а так
                                                                                    $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
                                                                                      А так имеем:
                                                                                      1. Notice
                                                                                      2. Необработана ситуация topicId = 0
                                                                                      3. Запросы в базу при отрицательном topicId
                                                                            0
                                                                            Запрос, в котором не выполняется условие intval($_GET['uid']) == $_GET['uid'], может быть вполне корректен семантически. Да и даже если нет, проще сделать холостой запрос, чем «пачкать» код проверками, если число холостых пренебрежимо мало.
                                                                              +1
                                                                              Можно несколько проще
                                                                              if (is_numeric($_GET['uid']))
                                                                              ...
                                                                              
                                                                                +3
                                                                                Вы ПХП-то знаете вообще? Суньте в _GET например такую строку: «9 AND UNION SELECT 1 FROM DUAL». Она чудесно пройдёт проверку.
                                                                                +4
                                                                                К строке

                                                                                $sql = "SELECT id FROM userslist WHERE username='" . mysql_real_escape_string($_GET['username']) . "'";
                                                                                

                                                                                К числу

                                                                                $sql = "SELECT user FROM userslist WHERE userid='" . intval($_GET['uid']) . "'";
                                                                                
                                                                                  0
                                                                                  Я обычно так пишу. Почти))

                                                                                  $sql = "SELECT `user` FROM `userslist` WHERE `userid`='" . intval($_GET['uid']) . "'";
                                                                                  


                                                                                  Не знаю, есть ли какой-то дополнительный смысл в наличии/отсутствии кавычек вокруг имен таблиц и столбцов, но мне так проще читать код
                                                                                    +4
                                                                                    В кавычках вокруг intval смысла нет, если userid число.
                                                                                      0
                                                                                      Я хотел бы услышать комментарий про другие кавычки)

                                                                                      В любом случае, предпочитаю ставить кавычки везде, в том числе вокруг 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
                                                                                        Не каждый держит в голове весь список зарезервированных слов :) Да и вдруг когда-нибудь появятся новые, а древний код все еще будет использоваться.
                                                                                      +3
                                                                                      Кстати, лучше всё-таки „(int)“, в ПХП вызов функции — дорогая операция.
                                                                                        +1
                                                                                        наконец-то кто-то это написал. Почему везде все пишут про intval(), когда дешевле и лучше просто воспользоваться приведением типов?
                                                                                      +3
                                                                                      Я использую библиотеку DbSimple от Котерова. На сколько мне известно, она используется и на этом движке, на котом хабр.
                                                                                        0
                                                                                        Аналогично. Использую допиленный DbSimple. Плюс писал свою версию с нуля для MSSQL, так как очень не хватало привычных методов при работе с этой СУБД.
                                                                                          +1
                                                                                          Ссылка: 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);
                                                                                          
                                                                                            0
                                                                                            Выглядит красиво, но как производится сама проверка?
                                                                                              +1
                                                                                              В комментарии я привел далеко не все плюшки.

                                                                                              Все подстановки с "?" экранируются как строки. Все элементы массивов при подстановке "?a" экранируются как строки, а ключи массивов при UPDATE и INSERT как идентификаторы (`name`).
                                                                                              Для подстановок с "?d" выполняется intval:
                                                                                              $topic = $db->selectRow('SELECT * FROM topics WHERE id = ?d', $_GET['id']);
                                                                                              
                                                                                              0
                                                                                              Использую goDB, там всё тоже, только вместо множества методов указывается формат в котором представлять результат:
                                                                                              $db->query('SELECT * FROM users WHERE name=?', array($name))->row()
                                                                                              
                                                                                            –4
                                                                                            А разв Хабр на php? Я почему-то думал, что он на asp.
                                                                                              +2
                                                                                              Ага, а куки PHPSESSID для маскировки :)
                                                                                            +1
                                                                                            Обычно использую:
                                                                                            ".select .. from ... where strcmp(field,'".$mustBeString."')=0 or id=".(int)$mustBeInt.";"
                                                                                            + ессно автоэкранирование кавычек в строках
                                                                                              +1
                                                                                              Мой сайт хакали именно через такую SQL инъекцию. Век живи, век учись.
                                                                                                0
                                                                                                если вы не знаете через что именно хакнули (какой запрос), как вы можете быть уверенным, что хакнули именно через SQL-инъекцию?
                                                                                                  0
                                                                                                  Взломщик оказался воспитанным и указал мне на ошибку.
                                                                                                    0
                                                                                                    повезло. По-больше бы таких взломщиков.
                                                                                                +1
                                                                                                Если заведомо число передается, всегда делают some sql query where id=".(int)$value."… а вообще стараюсь чтобы всегда только числа передавались, а уж если строка, то кучу перепроверок + экранирование.
                                                                                                Тут народ intval предлагает, чем то лучше или хуже (а то вдруг 6 лет зря (int) пихаю)?
                                                                                                  0
                                                                                                  (int) будет быстрее, чем intval()
                                                                                                    0
                                                                                                    Функцию, в отличие от модификатора, можно передать калбэком куда-нибудь (не защищаю его, просто предлагаю случаи, когда модификатор использовать не получится)
                                                                                                      0
                                                                                                      это уже совсем редкий случай, как мне кажется
                                                                                                        0
                                                                                                        Ну я просто привел пример различий :-)
                                                                                                    0
                                                                                                    Только параметризованные запросы. Никаких конкатенаций. В PHP есть параметризованные запросы? Простите давно не писал на нем, не помню.
                                                                                                      0
                                                                                                      в mysqli_* есть.
                                                                                                      +1
                                                                                                      А под фреимворки регулярки не составляли?)
                                                                                                      Когда нарочно обходят использование preapared statements конкатенацией.
                                                                                                        0
                                                                                                        Не составлял, сложно и муторно. Есть средства статического анализа кода, они позволяют выполнять эту работу более комплексно и не привязаны к конкретным конструкциями.
                                                                                                          0
                                                                                                          Средства статистического анализа кода, написанного на PHP-фреймворках?
                                                                                                          Не подскажите какой-нибудь? Буду благодарен.
                                                                                                          Статистический анализ кода так или иначе привязан к конкретным конструкциям.
                                                                                                            +1
                                                                                                            у нас своя разработка статического анализатора. Статический анализ привязан скорее уже не к конструкциям, а к структуре кода, скорее всего вы про это и говорили. Поэтому такие вещи как RIPS не справляются с ООП. Но если знать, что хочется найти, то, скажем, выполнить задачу «поиск всех функций где аргумент попадает в SQL запрос без фильтрации» выполнить можно быстро и качественно.
                                                                                                              0
                                                                                                              А, понятно, у вас свой анализатор. Просто думал какой-то инструмент используете с уже собранными регулярками.
                                                                                                              Действительно, теперь про анализ мы друг друга поняли.
                                                                                                              С последним, да, у меня у меня именно так: наткнулся на уязвимую конструкцию и грепаешь весь код на подобные, действительно, быстро и качественно.
                                                                                                                0
                                                                                                                Ага, тоже так делал, пока не устал эти регулярки писать. Очень много получается веб-приложений и все такие разные, что пришлось изобретать какую-то утилиту под свои нужды. В целом, посмотрите на TXL (http://www.txl.ca/ www.txl.ca/examples/Grammars/PHP/README.txt)
                                                                                                        0
                                                                                                        только экранирование, только хардкор!

                                                                                                        Only users with full accounts can post comments. Log in, please.