Заработок с сайта Скрипты
создание сайтов раскрутка сайтов поддержка сайтов
статьи справочик

Статьи -> Изучаем PHP -> Безопасность и ведение логов

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

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

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

 NoticeUndefined indexcontent in /usr/local/apache/htdocs/index.php on line 22 

Что нам может поведать это сообщение? Очевидно, то, что в коде есть массив с индексом content, неопределённый в строке 22 файла index.php. Благодаря этому сообщению, у злоумышленника есть подсказка о потенциальной дыре, через которую можно замусорить данные приложения. Может быть, это неопределённый индекс где-нибудь в $_GET или в $_POST. В принципе, смоделировать разные контексты и определив, как меняется при этом номер строки, где возникает ошибка, вы можете даже воссоздать общую идею работы скрипта. Кроме того, вид сообщения может также предоставить более подробную информацию о расположении файлов, с которыми работает скрипт (если мы работаем с функциями файловой системы), формат запросов (если работаем с базами данных), и прочие данные. Начнём с того, что обычно пользователям просто не нужно получать сообщение об ошибке со всеми подробностями, если что-то пошло не так. Ну а при определённых обстоятельствах такие подробности могут стать дырой в системе безопасности.

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

Механизм регистрации ошибок в PHP

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

Система регистрации ошибок в PHP может быть настолько простой или сложной, насколько вы пожелаете. В самом PHP есть выбор из нескольких встроенных механизмов обработки и регистрации ошибок. Например, PHP по умолчанию все ошибки выполнения скрипта выдаёт в браузер, но может быть сконфигурирован так, чтобы ошибки регистрировались, но не отображались. Это поведение контролируется из файла настройки php.ini директивами log_errors и display_errors. Включайте и выключайте сообщения об ошибках в зависимости от ваших программерских нужд. Обычная практика - это отображение ошибок без их регистрации на стадии разработки и отладки приложения. Для готового продукта всё наоборот: регистрация без отображения.

Как сообщения об ошибках PHP вываливаются в браузер, вы видели, а где PHP ведёт лог, если регистрация ошибок включена? Поведение механизма регистрации ошибок в PHP контролируется другой директивой, error_log. Значение может быть выставлено на имя файла, или на строку "syslog", или вовсе не выставлено (по умолчанию). В последнем случае, то есть когда значение error_log в php.ini не выставлено, то логи PHP ведутся за счёт средств web-сервера (например, Apache-вский error-log). Если значение выставлено на имя файла, то PHP будет писать лог в указанный файл, пока будут позволять системные разрешения. Если значение выставлено на ключевое слово syslog, то лог PHP будут вестись средствами журналирования операционной системы. Для UNIX-систем это стандартный системный журнал [syslog], для систем Windows NT и XP это журнал событий [event log].

PHP сам позаботится о регистрации ошибок, если вы используете встроенный обработчик ошибок, однако для своего обработчика (о нём речь пойдёт далее в статье) вам придётся всё сделать своими руками. Для подобных деяний PHP предлагает функцию error_log() со следующим синтаксисом:

 error_log($message [, $message_type [, $dest [, $extra_info]]]); 

В зависимости от выставленного значения необязательного параметра $message_type (ноль по умолчанию), произойдёт одно из нижеперечисленного:

Примечание: Вы наверняка заметили, что для значения $message_type равного 2 поведение не предусмотрено. Это рудимент от PHP версии 3, где удалённая отладка поставлялась в стандартном релизе как его часть. Для PHP4 это уже не так. Функцию error_log() можно использовать для ведения логов в любой части приложения, но, как правило, она применяется как часть своего обработчика ошибок. Примеры - в мануале.

Классификация ошибок в PHP

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

Устанавливаем режим вывода сообщений об ошибках

Директива конфигурации error_reporting определяет, какие сообщения об ошибках пишутся в лог или выбрасываются в браузер, когда оные ошибки случаются. Эта директива представляет собой "битовое поле", а это означает, что типы сообщений можно как угодно комбинировать с помощью логических операторов AND, OR, и NOT.В файле php.ini символ амперсанда (&) означает AND, символ конвейеризации (|) означает OR, а тильда (~) означает NOT. Таким образом, чтобы отображались или писались в лог только серьёзные ошибки, ваша директива примет следующий вид:

error_reporting = E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR

Помимо стандартных типов ошибок директива error_reporting принимает специальный тип, E_ALL, представляющий все возможные типы ошибок сразу, то есть как будто вы OR-ами соединила все стандартные типы. Приведённая ниже директива заставляет отображать или писать в лог все типы ошибок, кроме ошибок из коллекции E_USER:

error_reporting = E_ALL & ~E_USER_ERROR & ~E_USER_WARNING & ~E_USER_NOTICE

По умолчанию директива error_reporting сообщает в браузер или лог обо всех ошибках, кроме E_NOTICE.

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

<?php
echo @$myvar;
?>

не выкинет сообщение класса E_NOTICE, даже несмотря на то, что $myvar неопределена. Ошибку эту PHP проигнорирует и не напишет ничего.

Другой способ изменить настройку управления ошибками в PHP - это использовать функцию error_reporting(). Данная функция непосредственно изменяет "внутреннее" значение конфигурационной директивы error_reporting. Синтаксис функции таков:

 error_reporting([$error_value]) 

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

<?php
error_reporting
(E_ERROR E_CORE_ERROR E_COMPILE_ERROR E_USER_ERROR);
?>

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

<?php
$old_error 
error_reporting(0); /* Сообщения об ошибках больше не генерируем */
/* тут какой-то код */
error_reporting($old_error); /* восстанавливаем предыдущий режим вывода сообщений об ошибках. */
?>

Обработчики ошибок, определяемые программистом

Помимо встроенных средств обработки ошибок PHP также позволяет вам написать ваш собственный обработчик. Определённый вами лично обработчик ошибок позволяет вам осуществлять полный контроль над тем, как ваше web-приложение будет реагировать на ошибки, сгенерированы ли они PHP или сброшенные функцией trigger_error(). Чтобы задействовать определённую вами обработку ошибок, необходимо определить следующим способом:

<?php
function my_handler($error_code$error_msg [, $error_file [,
$error_line [, $vars]]]) {
    
/* Собственно реализация обработчика */
}
?>

Как описано в нашем примере, обработчик ошибок должен принимать параметры $error_code и $error_msg; первый - это класс ошибки (например, E_ERROR), а второй - это сообщение, привязанное к данному классу. Ваш обработчик ошибок способен принимать до трёх дополнительных параметров: $error_file, $error_line, и $vars. Первые два - это PHP-файл и строка в нём, где ошибка имела место. Последний параметр, $vars, представляет собой ассоциативный массив, в котором содержатся имя и значение каждой переменной, которые были в области видимости на момент возникновения ошибки.

Создав такую функцию, её надо зарегистрировать в PHP как действующий обработчик ошибок. Для этого используйте функцию set_error_handler(), синтаксис её таков:

 set_error_handler($func_name

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

Последняя функция на сегодня, trigger_error(). Эта функция используется для генерации ошибки, определённой разработчиком. Синтаксис функции таков:

 trigger_error($msg [, $error_code]) 

где $msg - это строка с сообщением и описанием об ошибке, а факультативный параметр $error_code - класс ошибки из коллекции E_USER. Если второй параметр опускается, PHP автоматически применяет E_USER_NOTICE. Функция trigger_error() предназначена для использования в связке с обработчиком, определённым программистом; однако если такой обработчик не был определён, PHP среагирует на ошибку через стандартный обработчик.
Если Вы заметили какие-либо неточности или ошибки в размещенной информации, просим сообщить о них администрации.