Глава 28. Сообщения об ошибках

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

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

Пример 28-1. Атака на переменные в HTML-странице

<form method="post" action="attacktarget?username=badfoo&amp;password=badfoo">
<input type="hidden" name="username" value="badfoo" />
<input type="hidden" name="password" value="badfoo" />
</form>

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

Пример 28-2. Использование стандартных отладочных переменных

<form method="post" action="attacktarget?errors=Y&amp;showerrors=1&amp;debug=1">
<input type="hidden" name="errors" value="Y" />
<input type="hidden" name="showerrors" value="1" />
<input type="hidden" name="debug" value="1" />
</form>

Независимо от метода обработки ошибок возможность проверки системы на наличие ошибок снабжает взломщика дополнительной информацией.

Например, стандартный вывод об ошибке указывает операционную систему, в которой выполняются PHP скрипты. Если взломщик анализирует обыкновенную HTML-страницу, пытаясь найти уязвимые места, используя ввод неверных данных он может обнаружить использование PHP скриптов в данной системе.

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

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

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

Один из возможных способов обезопасить ваш код перед его публикацией для общего доступа - индивидуальное использование error_reporting(), чтобы выявить потенциально опасные переменные. Тестируя код перед выпуском релиза при помощи значения E_ALL, вы достаточно легко можете обнаружить участки кода, в которых переменные могут быть подменены либо модифицированы. После окончания тестирования, установив значение E_NONE, вы можете полностью отключить вывод сообщений об ошибках.

Пример 28-3. Поиск потенциально опасных переменных при помощи E_ALL

<?php
if ($username) {  // Переменная не инициализируется перед использованием
    
$good_login = 1;
}
if (
$good_login == 1) { // Если предыдущая проверка потерпела неудачу, переменная оказывается неинициализированной
    
readfile ("/highly/sensitive/data/index.html");
}
?>