Специалисты по безопасности, пожалуй, всем уже проели плешь, говоря о том, что все данные, приходящие от пользователя, нужно тщательно проверять… Казалось бы, "азбучные истины", этому должны учить в школе . Мне стало интересно: а многие ли сайты действительно защищены?
Внимание: материал предоставлен только в ознакомительных/образовательных целях! Автор не несёт ответственности за всё, что может случиться. Данная статья не должна рассматриваться, как практическое руководство по взлому; статья является обзором наиболее типичных ошибок программистов и объясняет, как именно невнимательность разработчиков может служить источником дыр безопасности.
Одна из самых распространённых атак (я не беру DoS, DDoS и иже с ними) — это SQL Injection Attack.
Как пишет Wikipedia,
Инъекция SQL (англ. SQL injection) — один из распространённых способов взлома сайтов и программ, работающих с базами данных, основанный на внедрении в запрос произвольного SQL-кода.Инъекция SQL, в зависимости от типа используемой СУБД и условий инъекции, может дать возможность атакующему выполнить произвольный запрос к базе данных (например, прочитать содержимое любых таблиц, удалить, изменить или добавить данные), получить возможность чтения и/или записи локальных файлов и выполнения произвольных команд на атакуемом сервере.
Атака типа инъекции SQL может быть возможна из-за некорректной обработки входящих данных, используемых в SQL-запросах.
Как уже было сказано, такие атаки проходят из-за недостаточной обработки входных параметров скрипта. Нередки случаи, когда программисты-новички, полагают, что если ID записи — это число, то скрипт всегда будет получать именно число, а не строку. Простой пример реального кода:
$query = "SELECT * FROM {$members} WHERE id = $id LIMIT 1";
$res = mysql_query($query, $link);
Всем хорош код, когда $id — это число. Например, если скрипт был вызван "script.php?id=123", то запрос принял бы следуюший вид:
Всё хорошо, но встречаются нехорошие дяди, которые вместо числа могут скормить скрипту всякую каку: для данного простого примера достаточно передать скрипту в параметрах script.php?id=0%20OR%201, чтобы заставить его выбрать все записи (о том, как обойти LIMIT, чуть ниже). Фактически, запрос будет переписан в виде
Так как практически всегда для ID используются автоинкрементные поля, то выражение (id = 0)
будет всегда ложно. А (FALSE OR 1)
— всегда истинно.
Даже если запрос содержит LIMIT
, это не спасает от выборки произвольной записи: script.php?id=0%20OR%201%20LIMIT%20A,B/*%20--
Вместо A и B — значения для offset
и count
соответственно, например:
Что примечательно: MySQL успешно выполнит запрос не смотря на то, что комментарий-то не закрыт. А так как /* */
— многострочный комментарий, то запрос отлично выполнится, даже если он многострочный.
Есть и другой метод — более простой, но не всегда рабочий — просто передать скрипту нужный id и не ломать голову с запросом. Очевидно, что если скрипт делает выборку не только по id, но и по другому полю (например, WHERE `id` = 'id' AND `member_id` = 'member_id'
), то простая подмена числа не сработает. А инъекция будет работать.
Сама по себе техника простая, но очень эффективная и деструктивная. Когда я работал над сайтом uk-swingers.com (исправлял баги), я показал заказчику, как из его базы можно было воровать… номера кредитных карточек с кодами CVV, информацией о владельце и прочими данными. То, что хранение подобной информации в БД запрещено, это другая история… Да, он шифровал информацию в БД (при помощи алгоритма RC4 ). Да, он стирал 4 средние цифры из номера кредитки (через несколько часов после выполнения транзакции), но был ли в этом смысл? Дело в том, что данные могли быть зашифрованы как угодно, но браузеру они передавались в открытом виде. А номер кредитной карточки можно легко восстановить — во-первых, можно угадать BIN, исходя из территориальной близости к банку, во-вторых, перебором можно вычислить возможные номера карточки (для валидации номера используется формула Луна). На другом сайте (имя пока открыть не могу) так можно было читать чужие письма и воровать почтовые адреса и пароли (и устраивать кучу других гадостей).
Немного сложнее со строками. Я провел исследование, и выяснил, что если строка передается на сервер из <input type="hidden">
, то она далеко не всегда экранируется (особенно, если авторство кода принадлежит индусам).
Пример с реального сайта (кстати, писали даже не индусы, а вьетнамцы):
$query = "SELECT * FROM {$prefix}profiles WHERE user = '$name'";
$res = mysql_query($query, $link);
script.php?member=testdavid
Инъекция проходит аналогично: так как строки в MySQL заключаются в одинарные или двойные кавычки, то запрос модифицируется так, чтобы закрыть кавычку:
Аналогично вышеприведённому примеру, в запрос можно добавить LIMIT
и ORDER BY
.
Ладно, хватит голой теории, переходим к практике
Большую популярность получили сайты, публикующие различные статьи различных авторов: владельцы сайтов получают контент, авторы — обратную ссылку на свой сайт и возможность показывать свою рекламу. Таких сайтов много: articledashboard.com, articledirectory.com, webarticles.com и т.п.
Один из таких сайтов (articledashboard.com) писали индусы Заинтересовали они меня тем (articledashboard.com, не индусы), что они предлагали скачать "exact software that powers Article Dashboard for FREE". Кто не любит халяву
Хотя PHP-код зашифрован ionCube, индусское авторство доказывается наличием огромного файла functions.php (я подобное видел во всех проектах, когда приходилось переделывать код после индусов). А индусы не любят делать
addslashes()
. Тоже из опыта.
Приведу несколько скриншотов, показывающих наличие уязвимостей на сайте.
На сайте есть хорошая функция — загрузка своей аватарки. Казалось бы, что здесь можно сломать? Тем не менее, и описываемая ниже уязвимость сводится к недостаточной обработке входных данных.
Есть очень хороший extension для FireFox, который позволяет подделывать mime-type. То есть фактически мы можем проинструктировать FireFox посылать произвольный файл (например, php) с mime-type, соответствующим изображению (например, image/png). В том случае, если сервер проверяет тип файла только по данным, которые пришли со стороны пользователя, скрипт обманывает сам себя.
И на закуску: все эти сайты работают под ArticleDirectory.
А вы говорите, безопасность…
Мораль сей басни такова: никогда (еще раз подчёркиваю, никогда) нельзя доверять данным, которые пришли со стороны пользователя. Все данные нужно проверять и при проверках предполагать худшее. Естественно, это увеличивает размер кода и время написания программы. Но лучше заказчику потратить пару сотен долларов на безопасность, чем рвать волосы на голове после обнаружения взлома по факту.
Update: несколько дней назад я предупредил владельцев сайта Article Dashboard о том, что их ПО (а также то ПО, которое они распространяют) уязвимо. Ответа от них не последовало. Что же, отсутствие ответа — тоже ответ. Но вот только решение проблем безопасности страусиным методом еще не разу себя не оправдывало.
Ктож такие вещи в паблик выкладывает, да еще и с линком на список “жертв” до принятия мер со стороны разрабов?
Чего уж там про SQL-инъекции говорить, когда еще не все про XSS забыли (по некоторым оценкам Searchengines, число дырявых сайтов ~5-6%)
Разработчики забили на свой продукт. Я им даже решение постил. Метод страуса - не лучший метод защиты.
$id = $_GET['id'];
$query = “SELECT * FROM {$members} WHERE id = $id LIMIT 1″;
Всем хорош код, когда $id — это число. Например, если скрипт был вызван "script.php?id=123“, то запрос принял бы следуюший вид:
SELECT * FROM members WHERE id = 5 LIMIT 1
Это какая-то хитрая функция, которая изменила 123 на 5?
а ребята вообще забавные, даже файл твой не удалили
Спасибо, поправил…
Да забили они на сайт, они деньги с AdSense получают (кстати, Google AdSense забанил меня именно за эту статью); видимо, им этого хватает.
Повторил финт ушами. Покатаюсь по каталогам, ломать не буду
Честно, про подделку типа файла не думал.
Был уверен, что PHP лезет в файл, смотрит, что там, а потом выдает mime ))) Я был наивен, исправился.
Про плагин к ОгнеЛису - тоже спасибо, опять же не слышал о таком.
Ух, и интересно же все это )))
Еще одна статья по теме: Как не нужно интегрировать платёжные системы