Одним из наиболее значимых вопросов для web-программистов является безопасность php-скриптов. Все программисты в той или иной мере используют различные методы чтобы обезопасить свой проект, но, к сожалению, в большинстве случаев используется защита от нескольких уязвимостей, при этом остальные проблемные места даже не рассматриваются.
В данной статье перечислены основные виды уязвимостей PHP и рассмотрены способы защиты от них.
Виды уязвимостей PHP
1. Демонстрация ошибок пользователю
Смысл: при каких-либо ошибках в коде пользователю выводиться информация об произошедшей ошибке. Не является критичной уязвимостью, но поваляет взломщику получить дополнительную информацию о структуре и работе сервера.
2. Доступность данных о характеристиках системы пользователю
Смысл: пользователь может получить доступ к данным, дающим представление о системе. Не является критичной уязвимостью, но поваляет взломщику получить дополнительную информацию о структуре и работе сервера. Причина этой уязвимости в ошибках и «недосмотрах» программиста. Примером может служить наличие файла phpinfo.php с одноимённой функцией в свободном доступе.
3. Доступность данных о программном коде пользователю
Смысл: пользователь может получить доступ к программным кодам модулей, имеющих расширение, отличное от php. Является критичной уязвимостью, так как позваляет взломщику получить достаточно полную информацию о структуре и работе сервера, выявить его уязвимости.
4. Простые пароли для доступа к административным страницам
Смысл: взломщик может подобрать простой пароль к административной странице, дающей ему больше возможностей для взлома. Является критичной уязвимостью, так как позваляет взломщику повлиять на работу сервера.
5. Возможность задания глобальных переменных
Смысл: при неправильных настройках PHP имеется возможность задавать глобальные переменные скрипта, через строку запроса. Является критичной уязвимостью, так как взломщик может влиять на ход работы скрипта в свою пользу.
6. PHP-инъекция
Смысл: в параметр, определяющий работу PHP с файлами или программным кодом, передаётся ссылка на сторонний программный код или сам код. Является критичной уязвимостью, так как взломщик может выполнять свои скрипты на сервере. Выполнение кода осуществляется при помощи функций: eval(), preg_replace(), require_once(), include_once(), include(), require(), create_function(), readfile(), dir(), fopen().
7. PHP-инъекция через загрузку файлов
Смысл: при возможности задании глобальных переменных в параметр, определяющий загружаемый на сервер файл, передаётся ссылка на сторонний программный код или конфиденциальный файл на сервере. Является критичной уязвимостью, так как взломщик может выполнять свои скрипты на сервере или получить доступ к конфиденциальным данным. Данная уязвимость возможна только при возможности задания глобальных переменных и неверной организации механизма загрузки файлов.
8. e-mail-инъекция
Смысл: в параметр, определяющий работу PHP с электронными письмами, передаётся ссылка на сторонний программный код или сам код. Является критичной уязвимостью, так как взломщик может выполнять свои скрипты на сервере или получить доступ к данным, хранимым у пользователя.
9. SQL-инъекция
Смысл: в параметр, определяющий SQL-запрос, передаётся данные, образующее запрос для доступа к закрытым данным. Является критичной уязвимостью, так как взломщик может получить конфиденциальные данные, хранимые в базе данных. Для изменения запроса взломщик может использовать следующие конструкции: SELECT, UNION, UPDATE, INSERT, OR, AND.
10. Межсайтовый скриптинг или XSS
Смысл: в параметр, определяющий выводимые пользователю данные, передаётся сторонний программный код. Является критичной уязвимостью, так как взломщик может получить конфиденциальные данные, хранимые в браузере клиента. Для изменения запроса взломщик использует html-теги.
Правила написания безопасного кода на PHP
1. Блокирование вывода ошибок
Для этого достаточно в программном коде задать error_reporting(0) или в файле .htaccess добавить строку php_flag error_reporting 0
2. Использование сложных паролей для доступа к административным страницам
Для этого достаточно использовать многозначные пароли, не имеющие семантического значения (например, К7O0iV98dq).
3. Логирование критических действий пользователя
Не обеспечивает защиту напрямую, но позволяет выявить взломщиков и определить уязвимости, которые они использовали. Для этого действия пользователя и переданные им данные, которые касаются критических моментов работы системы, достаточно записывать в обычный текстовый файл.
Пример функции логирования и её работы:
function writelog($typelog, $log_text) {
$log = fopen('logs/'.$typelog.'.txt','a+');
fwrite($log, "$log_textrn");
fclose($log);
}
writelog('authorization', date("y.m.d H:m:s")."t".$_SERVER['REMOTE_ADDR']."tУспешный вход");
4. Закрытие доступа к модулям сайта
Обеспечивает защиту от попыток просмотра их содержимого или выполнения. Для этого достаточно в файле .htaccess настроить доступ к файлам модулей при помощи конструкций FilesMatch и Files.
Например, мы закрываем доступ ко всем модулям с расширением php, кроме файла capcha.php:
Order Deny,Allow
Deny from all
Allow from all
Отключение возможности задания глобальных переменных
Для этого достаточно в настройках сервера задать register_globals = off; или в файле .htaccess добавить строку php_flag register_globals off. Использование ini_set('register_globals',0); проблему не решит так, как переменные задаются до начала выполнения скрипта.
Отключение возможности использования удаленных файлов
Для этого достаточно в настройках сервера задать allow_url_fopen = off;. Это обеспечивает частичную защиту от PHP-инъекций, но не полную, так как взломщик может передавать не ссылку на файл с программным кодом, а сам программный код. Для полной защиты от PHP-инъекций необходимо дополнительно использовать фильтрацию поступивших данных. Иногда данную меру защиты невозможно использовать из-за особенностей работы проекта (нужно обращаться к удалённым файлам).
Фильтрация поступающих данных
Обеспечивает защиту от большенства уязвимостей. Универсального решения не существует. Желательно использовать проверку по «белому» списку символов в совокупности с проверкой на запрещённые слова. «Белым» называется список разрешенных символов. В этот список не должны входить опасные символы, например, <>. К запрещённым словам можно отнести: script, http, SELECT, UNION, UPDATE, exe, exec, INSERT, tmp, а также html-теги.
Пример фильтрации поступающих данных:
// Проверка по белому списку. Допускаются только русские и латинские буквы, цифры и знаки _-
if (preg_match("/[^(w)|(А-Яа-я-)|(s)]/",$text)) {
$text = '';
}
// Фильтрация опасных слов
if (preg_match("/script|http|<|>|<|>|SELECT|UNION|UPDATE|exe|exec|INSERT|tmp/i",$text)) {
$text = '';
}
Проверка на загрузку файла при помощи HTTP POST
Обеспечивает защиту от PHP-инъекций через загрузку файлов. Для обеспечения этого загруженные на сервер файлы необходимо проверять функцией is_uploaded_file() или перемещать функцией move_uploaded_file(). Данный вид защиты можно не использовать, если отключена возможность задания глобальных переменных.
Экранирование символов кавычек данных, передаваемых в базу данных
Обеспечивает защиту от SQL-инъекций. Наиболее оптимальным методом является обработка всех поступивших не числовых данных с помощью функции mysql_real_escape_string(). Можно так же использовать автоматическое экранирование, поступающих данных. Для этого достаточно в файле .htaccess добавить строку php_value magic_quotes_gpc on, но этот способ не является надёжным, так как может привести к двойному экранированию.
Пример экранирования кавычек с помощью функции mysql_real_escape_string():
if (!is_numeric($text)) {
$textrequest = mysql_real_escape_string($text);
}
Преобразование специальных символов в html-сущности перед выводом
Обеспечивает защиту от XSS. Для этого данные, введенные пользователем, которые могут содержать нежелательные html-тэги, при выводе достаточно обработать функцией htmlspecialchars(). Данный вид защиты можно не использовать, если фильтрация поступающих данных отсеивает опасные html-тэги.
Как видите создание продуманной системы безопасности скриптов не такое трудоёмкое дело.
Данная статья не претендует на роль учебника по безопасности скриптов, но Я надеюсь, что она подтолкнёт php-программистов использовать более продуманные методы защиты.
И еще немного на эту тему
Статус Error с 99% точностью говорит о том, что в данном месте есть XSS или SQL Injection уязвимость.
Строка кода с таким статусом может выглядеть например так:
echo $_GET['name'];
В такой ситуации при передаче в адресной строке параметра name таким образом &name= вы выделите болдом весь текст следующий за echo на сайте. Примеры могут быть и страшнее, вот один из них:
mysql_query("SELECT * FROM users WHERE user_id = ".$_GET['id']);
И если параметр в адресной строке будет выглядеть так &id=(DROP TABLE users) то такой запрос удалит таблицу users с вашего сайта. Такая атака называется SQL Injection.
Защитой в таких ситуациях является проверка получаемых от пользователя данных. В первом случае можно применить такие функции:
echo htmlentities(addslashes($_GET['name']));
А во втором случае целесообразно будет сделать так:
mysql_query("SELECT * FROM users WHERE user_id = ".intval($_GET['id']));
Сделав такие действия вы защитите свой сайт от такой уязвимости.
В данной статье перечислены основные виды уязвимостей PHP и рассмотрены способы защиты от них.
Виды уязвимостей PHP
1. Демонстрация ошибок пользователю
Смысл: при каких-либо ошибках в коде пользователю выводиться информация об произошедшей ошибке. Не является критичной уязвимостью, но поваляет взломщику получить дополнительную информацию о структуре и работе сервера.
2. Доступность данных о характеристиках системы пользователю
Смысл: пользователь может получить доступ к данным, дающим представление о системе. Не является критичной уязвимостью, но поваляет взломщику получить дополнительную информацию о структуре и работе сервера. Причина этой уязвимости в ошибках и «недосмотрах» программиста. Примером может служить наличие файла phpinfo.php с одноимённой функцией в свободном доступе.
3. Доступность данных о программном коде пользователю
Смысл: пользователь может получить доступ к программным кодам модулей, имеющих расширение, отличное от php. Является критичной уязвимостью, так как позваляет взломщику получить достаточно полную информацию о структуре и работе сервера, выявить его уязвимости.
4. Простые пароли для доступа к административным страницам
Смысл: взломщик может подобрать простой пароль к административной странице, дающей ему больше возможностей для взлома. Является критичной уязвимостью, так как позваляет взломщику повлиять на работу сервера.
5. Возможность задания глобальных переменных
Смысл: при неправильных настройках PHP имеется возможность задавать глобальные переменные скрипта, через строку запроса. Является критичной уязвимостью, так как взломщик может влиять на ход работы скрипта в свою пользу.
6. PHP-инъекция
Смысл: в параметр, определяющий работу PHP с файлами или программным кодом, передаётся ссылка на сторонний программный код или сам код. Является критичной уязвимостью, так как взломщик может выполнять свои скрипты на сервере. Выполнение кода осуществляется при помощи функций: eval(), preg_replace(), require_once(), include_once(), include(), require(), create_function(), readfile(), dir(), fopen().
7. PHP-инъекция через загрузку файлов
Смысл: при возможности задании глобальных переменных в параметр, определяющий загружаемый на сервер файл, передаётся ссылка на сторонний программный код или конфиденциальный файл на сервере. Является критичной уязвимостью, так как взломщик может выполнять свои скрипты на сервере или получить доступ к конфиденциальным данным. Данная уязвимость возможна только при возможности задания глобальных переменных и неверной организации механизма загрузки файлов.
8. e-mail-инъекция
Смысл: в параметр, определяющий работу PHP с электронными письмами, передаётся ссылка на сторонний программный код или сам код. Является критичной уязвимостью, так как взломщик может выполнять свои скрипты на сервере или получить доступ к данным, хранимым у пользователя.
9. SQL-инъекция
Смысл: в параметр, определяющий SQL-запрос, передаётся данные, образующее запрос для доступа к закрытым данным. Является критичной уязвимостью, так как взломщик может получить конфиденциальные данные, хранимые в базе данных. Для изменения запроса взломщик может использовать следующие конструкции: SELECT, UNION, UPDATE, INSERT, OR, AND.
10. Межсайтовый скриптинг или XSS
Смысл: в параметр, определяющий выводимые пользователю данные, передаётся сторонний программный код. Является критичной уязвимостью, так как взломщик может получить конфиденциальные данные, хранимые в браузере клиента. Для изменения запроса взломщик использует html-теги.
Правила написания безопасного кода на PHP
1. Блокирование вывода ошибок
Для этого достаточно в программном коде задать error_reporting(0) или в файле .htaccess добавить строку php_flag error_reporting 0
2. Использование сложных паролей для доступа к административным страницам
Для этого достаточно использовать многозначные пароли, не имеющие семантического значения (например, К7O0iV98dq).
3. Логирование критических действий пользователя
Не обеспечивает защиту напрямую, но позволяет выявить взломщиков и определить уязвимости, которые они использовали. Для этого действия пользователя и переданные им данные, которые касаются критических моментов работы системы, достаточно записывать в обычный текстовый файл.
Пример функции логирования и её работы:
function writelog($typelog, $log_text) {
$log = fopen('logs/'.$typelog.'.txt','a+');
fwrite($log, "$log_textrn");
fclose($log);
}
writelog('authorization', date("y.m.d H:m:s")."t".$_SERVER['REMOTE_ADDR']."tУспешный вход");
4. Закрытие доступа к модулям сайта
Обеспечивает защиту от попыток просмотра их содержимого или выполнения. Для этого достаточно в файле .htaccess настроить доступ к файлам модулей при помощи конструкций FilesMatch и Files.
Например, мы закрываем доступ ко всем модулям с расширением php, кроме файла capcha.php:
Order Deny,Allow
Deny from all
Allow from all
Отключение возможности задания глобальных переменных
Для этого достаточно в настройках сервера задать register_globals = off; или в файле .htaccess добавить строку php_flag register_globals off. Использование ini_set('register_globals',0); проблему не решит так, как переменные задаются до начала выполнения скрипта.
Отключение возможности использования удаленных файлов
Для этого достаточно в настройках сервера задать allow_url_fopen = off;. Это обеспечивает частичную защиту от PHP-инъекций, но не полную, так как взломщик может передавать не ссылку на файл с программным кодом, а сам программный код. Для полной защиты от PHP-инъекций необходимо дополнительно использовать фильтрацию поступивших данных. Иногда данную меру защиты невозможно использовать из-за особенностей работы проекта (нужно обращаться к удалённым файлам).
Фильтрация поступающих данных
Обеспечивает защиту от большенства уязвимостей. Универсального решения не существует. Желательно использовать проверку по «белому» списку символов в совокупности с проверкой на запрещённые слова. «Белым» называется список разрешенных символов. В этот список не должны входить опасные символы, например, <>. К запрещённым словам можно отнести: script, http, SELECT, UNION, UPDATE, exe, exec, INSERT, tmp, а также html-теги.
Пример фильтрации поступающих данных:
// Проверка по белому списку. Допускаются только русские и латинские буквы, цифры и знаки _-
if (preg_match("/[^(w)|(А-Яа-я-)|(s)]/",$text)) {
$text = '';
}
// Фильтрация опасных слов
if (preg_match("/script|http|<|>|<|>|SELECT|UNION|UPDATE|exe|exec|INSERT|tmp/i",$text)) {
$text = '';
}
Проверка на загрузку файла при помощи HTTP POST
Обеспечивает защиту от PHP-инъекций через загрузку файлов. Для обеспечения этого загруженные на сервер файлы необходимо проверять функцией is_uploaded_file() или перемещать функцией move_uploaded_file(). Данный вид защиты можно не использовать, если отключена возможность задания глобальных переменных.
Экранирование символов кавычек данных, передаваемых в базу данных
Обеспечивает защиту от SQL-инъекций. Наиболее оптимальным методом является обработка всех поступивших не числовых данных с помощью функции mysql_real_escape_string(). Можно так же использовать автоматическое экранирование, поступающих данных. Для этого достаточно в файле .htaccess добавить строку php_value magic_quotes_gpc on, но этот способ не является надёжным, так как может привести к двойному экранированию.
Пример экранирования кавычек с помощью функции mysql_real_escape_string():
if (!is_numeric($text)) {
$textrequest = mysql_real_escape_string($text);
}
Преобразование специальных символов в html-сущности перед выводом
Обеспечивает защиту от XSS. Для этого данные, введенные пользователем, которые могут содержать нежелательные html-тэги, при выводе достаточно обработать функцией htmlspecialchars(). Данный вид защиты можно не использовать, если фильтрация поступающих данных отсеивает опасные html-тэги.
Как видите создание продуманной системы безопасности скриптов не такое трудоёмкое дело.
Данная статья не претендует на роль учебника по безопасности скриптов, но Я надеюсь, что она подтолкнёт php-программистов использовать более продуманные методы защиты.
И еще немного на эту тему
Статус Error с 99% точностью говорит о том, что в данном месте есть XSS или SQL Injection уязвимость.
Строка кода с таким статусом может выглядеть например так:
echo $_GET['name'];
В такой ситуации при передаче в адресной строке параметра name таким образом &name= вы выделите болдом весь текст следующий за echo на сайте. Примеры могут быть и страшнее, вот один из них:
mysql_query("SELECT * FROM users WHERE user_id = ".$_GET['id']);
И если параметр в адресной строке будет выглядеть так &id=(DROP TABLE users) то такой запрос удалит таблицу users с вашего сайта. Такая атака называется SQL Injection.
Защитой в таких ситуациях является проверка получаемых от пользователя данных. В первом случае можно применить такие функции:
echo htmlentities(addslashes($_GET['name']));
А во втором случае целесообразно будет сделать так:
mysql_query("SELECT * FROM users WHERE user_id = ".intval($_GET['id']));
Сделав такие действия вы защитите свой сайт от такой уязвимости.