![]() |
Безопасность в Php, Часть Iii
Добро пожаловать к нам опять, в цикл статей по основам PHP. В прошлый раз, я распространялся о потенциальных брешах в безопасности, которые могут возникнуть при использовании системных вызовов в PHP-скриптах (и о некоторых методах защиты). Эта мини-серия статей посвящёна подводным камням при написании защищённых PHP-приложений; однако же, в последней моей статье я не буду рассказывать вам о каких-либо новых дырах в безопасности. Я считаю, что лучшим завершением нашего разговора о безопасности будут рассказ о средствах обработки и протоколирования ошибок, и краткая ретроспектива всего изложенного в этой мини-серии.
Безопасность и ведение логов Злоумышленнику, чтобы использовать ваш код в своих целях, нужно сначала определить его слабые места. Это достигается зондированием вашего приложения и сбором как можно большего количества информации о нём. Самый распространённый и эффективный способ - это попытки вызвать ошибки приложения.. Предположим, например, что злоумышленник ввёл некорректные данные в поле login-формы и спровоцировал следующее стандартное сообщение об ошибке в PHP: PHP код:
Первый шаг в решении этой проблемы - всевозможные меры по сокращению появления ошибок в скриптах. В каждом уважающем себя 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() со следующим синтаксисом: PHP код:
если $message_type равен нулю, то сообщение об ошибке $message будет записано в лог, указанный в директиве конфигурации error_log. если $message-type равен 1, то сообщение об ошибке $message будет отправлено по электронной почте на адрес, указанный в параметре $dest. Любые дополнительные почтовые заголовки можно указать в параметре $extra_info. если $message_type равен 3, то сообщение об ошибке $message будет записано в файл, указанный в параметре $dest. Примечание: Вы наверняка заметили, что для значения $message_type равного 2 поведение не предусмотрено. Это рудимент от PHP версии 3, где удалённая отладка поставлялась в стандартном релизе как его часть. Для PHP4 это уже не так. Функцию error_log() можно использовать для ведения логов в любой части приложения, но, как правило, она применяется как часть своего обработчика ошибок. Примеры - в мануале. Классификация ошибок в PHP Понимание классификации ошибок PHP, почти также важнО как правильная настройка системы регистрации ошибок. Данная модель определяет, какие типы ошибок регистрируются, как и когда происходит регистрация. Чтобы осмыслить саму модель классификации, вам нужно знать, какие типы ошибок вы можете получить в PHP, и каково значение каждой из них. Эти знания вы можете почерпнуть из мануала или из представленного ниже списка: E_ERROR означает, что в самом PHP или в одном из его расширений возникла серьёзная внутренняя проблема (например, невозможность выделить память). E_WARNING обычно выдаётся с целью привлечь внимание к потенциальной ошибке в коде, из-за которой он возможно будет работать не так, как задумано. Пример: какой-либо встроенной функции передаётся скалярное значение вместо ожидаемого составного, например массива. E_NOTICE - это наименее значительная встроенная ошибка PHP. Этот тип почти никогда не означает, что приложение работает неправильно. Сообщения об ошибках этого типа призвано предупредить разработчика о таких вещах, как использование переменных до инициализации. E_CORE_ERROR по фатальности равно E_ERROR, но выдаётся только при запуске ядра PHP. E_CORE_WARNING - не фатальный коллега E_CORE_ERROR и схож с E_WARNING. выдаётся только при запуске ядра PHP. E_COMPILE_ERROR означает серьёзную ошибку во время компиляции движком Zend Scripting Engine. E_COMPILE_WARNING предупреждение, нефатально, как и E_WARNING, генерируется во время компиляции движком Zend Scripting Engine. E_USER_ERROR зарезервирован исключительно для использования с функцией trigger_error() (см. далее в статье). По умолчанию обработка та же, что и у E_ERROR: сообщение об ошибке и прекращение исполнения. E_USER_WARNING зарезервирован исключительно для использования с функцией trigger_error().По умолчанию обработка та же , что и у E_WARNING. E_USER_NOTICE зарезервирован исключительно для использования с функцией trigger_error(). В отличие от E_NOTICE, который игнорируется по умолчанию, PHP выдаст сообщение о E_USER_NOTICE пользователю. Устанавливаем режим вывода сообщений об ошибках Директива конфигурации 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 код:
Другой способ изменить настройку управления ошибками в PHP - это использовать функцию error_reporting(). Данная функция непосредственно изменяет "внутреннее" значение конфигурационной директивы error_reporting. Синтаксис функции таков: PHP код:
PHP код:
PHP код:
Помимо встроенных средств обработки ошибок PHP также позволяет вам написать ваш собственный обработчик. Определённый вами лично обработчик ошибок позволяет вам осуществлять полный контроль над тем, как ваше web-приложение будет реагировать на ошибки, сгенерированы ли они PHP или сброшенные функцией trigger_error(). Чтобы задействовать определённую вами обработку ошибок, необходимо определить следующим способом: PHP код:
Создав такую функцию, её надо зарегистрировать в PHP как действующий обработчик ошибок. Для этого используйте функцию set_error_handler(), синтаксис её таков: PHP код:
Действие вашего обработчика не распространяется на "фатальные" ошибки. Ваш обработчик будет вызываться только для ошибок класса E_WARNING, E_NOTICE и коллекции E_USER. Для всех прочих ошибок будет вызываться встроенный обработчик, как если бы вы вовсе не определяли свой альтернативный обработчик. Если задействован обработчик, определённый программистом, PHP будет вызывать его при возникновении любой из вышеперечисленных ошибок, конфигурационная директива error_reporting игнорируется. Какая-либо реакция на error_reporting() определяется также в обработчике. Если только исполнение скрипта не прерывается в обработчике с помощью die() или exit(), скрипт продолжит работу, невзирая на класс ошибки. Прекращение работы скрипта при необходимости определяется в обработчике. Последняя функция на сегодня, trigger_error(). Эта функция используется для генерации ошибки, определённой разработчиком. Синтаксис функции таков: PHP код:
В качестве резюме В завершение этой мини-серии, посвящённой некоторым аспектам безопасности в PHP, я хотел бы ещё раз обозначить тезисы трёх статей. При написании web-приложения на PHP (да и любых других приложений на любом же языке), самое большее, что вы можете сделать для повышения уровня безопасности в вашем приложении - это держать в голове все возможные пути компрометации оной безопасности. Используются ли системные вызовы? Что делается для их защиты от непредусмотренного использования? Как приложение будет реагировать на некорректные данные от пользователя? Какие меры предусмотрены для фильтрации данных, полученных от пользователя? При разработке приложения вы должны всегда задавать себе все эти вопросы. В конечном счёте, любой текст (включая тот, что у вас перед глазами) может только лишь чему-то научить. Вы получили некоторые начальные знания о ведении логов и проверке данных на корректность, вам же и решать, будете ли вы применять эти знания в разработке ваших приложений. Тщательность и внимательное отношение к каждой детали - лучшие инструменты разработчика при создании системы защиты для приложения. Конечно, злоумышленники используют стандартные средства, чтобы заставить ваше приложение повести себя непредвиденным образом. Однако сама природа злого умысла говорит о том, что всегда найдётся то, чего вы не предусмотрели. А раз найдено, значит использовано. В моей следующей статье я немного сбавлю обороты и от безопасности перейду к обзору различных инструментов для работы с данными и управления ими. Итак, до встречи, счастливо покодить! Джон Коггсхол (John Coggeshall): специалист и один из создателей PHP. Недосыпания по причине PHP начались около пяти лет назад. Автор: Данил Миронов |
| Время: 22:40 |