Ответ 1
Сохранение простоты. Как это должно быть просто: -)
Ваш первый фрагмент кода
libxml_disable_entity_loader
делает или ничего не делает здесь, исходя из того, решает ли ваша система по умолчанию или нет (мой не работает). Это контролируется опцией LIBXML_NOENT
libxml.
Без этого процессор документов может даже не попробовать переводить внешние сущности, и поэтому libxml_disable_entity_loader
не имеет ничего действительного влияния (если libxml не загружает объекты по умолчанию, что, похоже, имеет место в вашем тестовом случае).
Добавьте LIBXML_NOENT
в loadXML()
следующим образом:
$dom->loadXML($xml, LIBXML_NOENT);
и вы быстро получите:
PHP Warning: DOMDocument::loadXML(): I/O warning : failed to load external entity "/etc/passwd" in ...
PHP Warning: DOMDocument::loadXML(): Failure to process entity c in Entity, line: 7 in ...
PHP Warning: DOMDocument::loadXML(): Entity 'c' not defined in Entity, line: 7 in ...
Второй фрагмент кода
В этом случае вы разрешили обработку объекта с помощью параметра LIBXML_NOENT
, поэтому он идет после /etc/passwd
.
Этот пример отлично работает на моей машине даже для внешнего URL-адреса - я изменил ENTITY
на внешний:
<!ENTITY c PUBLIC "bar" "https://stackoverflow.com/opensearch.xml">
На него, однако, можно влиять, например. allow_url_fopen
Настройка PHP INI - установите значение false, и PHP никогда не загрузит удаленный файл.
Ваш третий фрагмент кода
XML Сущность, которую вы предоставили, не является внешней, а скорее внутренней (см., например, здесь).
Ваше лицо:
<!ENTITY c "Blah blah">
Как определяется внутренняя сущность:
<!ENTITY % name "entity_value">
Поэтому нет причин для PHP или libxml для предотвращения разрешения такой сущности.
Заключение
Я быстро выложил PHP XXE тестер script, который пытается выполнить различные настройки и показывает, успешна ли XXE и в этом случае.
Единственная строка, которая должна фактически показывать предупреждение, это "LIBXML_NOENT".
Если какая-либо другая строка загружает WARNING, external entity loaded!
, ваша настройка позволяет загружать внешние объекты по умолчанию.
Вы не можете ошибаться при использовании СЛЕДУЕТ ИСПОЛЬЗОВАТЬ libxml_disable_entity_loader() независимо от настроек вашего/вашего поставщика по умолчанию. Если ваше приложение когда-либо мигрировало, оно может стать уязвимым мгновенно.
правильное использование
Как MediaWiki заявляет в ссылке, которую вы опубликовали.
К сожалению, способ, которым libxml2 реализует отключение, библиотека искалечена, когда внешние сущности отключены, а функции, которые в противном случае были бы безопасными, вызывают исключение во всем анализе.
$oldValue = libxml_disable_entity_loader(true);
// do whatever XML-processing related
libxml_disable_entity_loader($oldValue);
Примечание. libxml_disable_entity_loader() также запрещает загрузку внешних XML файлов напрямую (не через сущности):
<?php
$remote_xml = "https://stackoverflow.com/opensearch.xml";
$dom = new DOMDocument();
if ($dom->load($remote_xml) !== FALSE)
echo "loaded remote xml!\n";
else
echo "failed to load remote xml!\n";
libxml_disable_entity_loader(true);
if ($dom->load($remote_xml) !== FALSE)
echo "loaded remote xml after libxml_disable_entity_loader(true)!\n";
else
echo "failed to remote xml after libxml_disable_entity_loader(true)!\n";
На моей машине:
loaded remote xml!
PHP Warning: DOMDocument::load(): I/O warning : failed to load external entity "https://stackoverflow.com/opensearch.xml" in ...
failed to remote xml after libxml_disable_entity_loader(true)!
Возможно, это связано с этой ошибкой PHP, но PHP действительно глупо об этом:
libxml_disable_entity_loader(true);
$dom->loadXML(file_get_contents($remote_xml));
отлично работает.