#php #xml #xml-parsing
Вопрос:
<?php
$str = <<<XML
<?xml version="1.0"?>
<!DOCTYPE doc [
<!ENTITY e SYSTEM "/tmp/exp">
]>
<tag>amp;e;</tag>
XML;
$xml = new SimpleXMLElement($str);
echo $xml;
?>
Это должно выводить содержимое /tmp/exp
, но не выводит, и я не понимаю, почему, даже когда я запускаю сценарий с sudo
/tmp/exp
правами доступа к файлам или изменяю 777
их на .
Комментарии:
1. Попробуйте передать
LIBXML_NOENT
в качестве второго аргумента конструктору: 3v4l.org/nTvDp2. @ChrisHaas Это сработало, спасибо!
3. @ChrisHaas Прежде чем рекомендовать включить эту опцию, вы должны понять, почему она не включена по умолчанию: она связана со многими уязвимостями безопасности, поэтому ее необходимо использовать с осторожностью.
4. @IMSoP, я на 100% согласен, но также кажется, что это может быть то, к чему стремится операция.
5. @ChrisHaas Не обязательно; очевидно, что пример в моем ответе является нереалистично строгим фильтром, но главное, что у вас может быть белый список, из которого должны загружаться объекты — например, вряд ли будет законное использование для загрузки
/etc/passwd
Ответ №1:
Загрузка внешних объектов по умолчанию отключена, поскольку это может привести к различным уязвимостям безопасности.
Чтобы безопасно включить его, вам необходимо зарегистрировать пользовательский загрузчик сущностей, который может проверять ожидаемые пути к сущностям и решать, загружать ли их. Например, вы можете разрешить любой файл в определенном каталоге, но не в другом месте на диске — вам, вероятно, не нужно разрешать ссылки на системные файлы, такие как /etc/passwd
. Или вы можете сопоставить указанный путь с совершенно другим местоположением в вашей системе.
Затем вам также необходимо предоставить LIBXML_NOENT
возможность указать синтаксическому анализатору развернуть объекты с помощью вашего обработчика.
Например:
libxml_set_external_entity_loader(function($public, $system, $context) {
if ($system === '/tmp/exp') {
return fopen('/tmp/exp', 'r');
}
else {
return null;
}
});
$xml = new SimpleXMLElement($str, LIBXML_NOENT);