PHP 8.3: Проблемы безопасности парсинга INI-строк и файлов
parse_ini_string
и parse_ini_file
, которые повторно используют встроенный в PHP синтаксический анализатор, применяемый для собственных конфигурационных файлов PHP на основе INI.Помимо разбора текста, парсер INI поддерживает наследование значений системного окружения и констант PHP, объявленных к моменту разбора текста. Начиная с версии PHP 8.3, он также поддерживает синтаксис запасных (fallback) значений для переменных окружения.
; Нормальные строковые литералы
my_config_name = normal
; Наследование переменной окружения SESSION_NAME или "", если она недоступна
my_config_name = ${SESSION_NAME}
; Наследование переменной окружения SESSION_NAME с запасным значением "MyDefaultValue"
my_config_name = ${SESSION_NAME:-MyDefaultValue}
; Интерполяция строк с переменными окружения
my_config_name = "${MAIL_FROM_USER}@${MAIL_FROM_DOMAIN}"
; Наследование PHP-константы PHP_VERSION
my_config_name = PHP_VERSION
Хотя эти усовершенствования полезны для конфигурирования PHP с помощью переменных окружения и использования доступных PHP-констант, использование встроенного PHP-парсера для анализа INI-значений, предоставленных пользователем, может стать уязвимостью безопасности, поскольку PHP можно обманом заставить раскрыть переменные окружения и PHP-константы, которые, скорее всего, содержат конфиденциальные данные, не подлежащие раскрытию.
Например, конфигурационный файл, предоставленный пользователем или удалённым сервером, которому нет полного доверия, может использовать это для того, чтобы обмануть сервер парсинга и раскрыть свои собственные переменные окружения и константы PHP:
; config.ini
plugin.name = "Free plugin ${DATABASE_NAME} / ${DATABASE_PASSWORD}"
plugin.description = DATABASE_PASSWORD
$conig = parse_ini_file('config.ini');
array(2) {
["plugin.name"]=> string(33) "Free plugin MyDbName / MyPa$$word"
["plugin.description"]=> string(10) "MyPa$$word"
}
Однако в PHP предусмотрены параметры конфигурации, позволяющие отключить принудительное использование типов и подстановку окружения/констант. Третий параметр функций parse_ini_file
и parse_ini_string
принимает битовую маску, и одним из принимаемых флагов является INI_SCANNER_RAW
, который отключает парсинг PHP типов, переменных окружения и констант PHP:
; config.ini
plugin.name = "Free plugin ${DATABASE_NAME} / ${DATABASE_PASSWORD}"
plugin.description = DATABASE_PASSWORD
$conig = parse_ini_file('config.ini', scanner_mode: INI_SCANNER_RAW);
// или
$conig = parse_ini_file('config.ini', false, INI_SCANNER_RAW);
array(2) {
["plugin.name"]=> string(51) "Free plugin ${DATABASE_NAME} / ${DATABASE_PASSWORD}"
["plugin.description"]=> string(17) "DATABASE_PASSWORD"
}
Предосторожность здесь заключается в том, что PHP не использует по умолчанию флаг INI_SCANNER_RAW
, а значит, все вызовы функций, не передающие явно флаг INI_SCANNER_RAW
, будут уязвимы, если они анализируют INI-значения, предоставленные пользователем.