mirror of
https://github.com/kamilwylegala/cakephp2-php8.git
synced 2024-11-15 03:18:26 +00:00
Fix XML decoding attack via external entities.
This commit is contained in:
parent
46f8de72a2
commit
6c905411ba
2 changed files with 51 additions and 13 deletions
|
@ -1039,4 +1039,22 @@ XML;
|
|||
$this->assertContains('mark & mark', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that entity loading is disabled by default.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testNoEntityLoading() {
|
||||
$file = CAKE . 'VERSION.txt';
|
||||
$xml = <<<XML
|
||||
<!DOCTYPE cakephp [
|
||||
<!ENTITY payload SYSTEM "file://$file" >]>
|
||||
<request>
|
||||
<xxe>&payload;</xxe>
|
||||
</request>
|
||||
XML;
|
||||
$result = Xml::build($xml);
|
||||
$this->assertEquals('', (string)$result->xxe);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -74,6 +74,8 @@ class Xml {
|
|||
* ### Options
|
||||
*
|
||||
* - `return` Can be 'simplexml' to return object of SimpleXMLElement or 'domdocument' to return DOMDocument.
|
||||
* - `loadEntities` Defaults to false. Set to true to enable loading of `<!ENTITY` definitions. This
|
||||
* is disabled by default for security reasons.
|
||||
* - If using array as input, you can pass `options` from Xml::fromArray.
|
||||
*
|
||||
* @param string|array $input XML string, a path to a file, an URL or an array
|
||||
|
@ -86,32 +88,50 @@ class Xml {
|
|||
$options = array('return' => (string)$options);
|
||||
}
|
||||
$defaults = array(
|
||||
'return' => 'simplexml'
|
||||
'return' => 'simplexml',
|
||||
'loadEntities' => false,
|
||||
);
|
||||
$options = array_merge($defaults, $options);
|
||||
|
||||
if (is_array($input) || is_object($input)) {
|
||||
return self::fromArray((array)$input, $options);
|
||||
} elseif (strpos($input, '<') !== false) {
|
||||
if ($options['return'] === 'simplexml' || $options['return'] === 'simplexmlelement') {
|
||||
return new SimpleXMLElement($input, LIBXML_NOCDATA);
|
||||
}
|
||||
$dom = new DOMDocument();
|
||||
$dom->loadXML($input);
|
||||
return $dom;
|
||||
return self::_loadXml($input, $options);
|
||||
} elseif (file_exists($input) || strpos($input, 'http://') === 0 || strpos($input, 'https://') === 0) {
|
||||
if ($options['return'] === 'simplexml' || $options['return'] === 'simplexmlelement') {
|
||||
return new SimpleXMLElement($input, LIBXML_NOCDATA, true);
|
||||
}
|
||||
$dom = new DOMDocument();
|
||||
$dom->load($input);
|
||||
return $dom;
|
||||
$input = file_get_contents($input);
|
||||
return self::_loadXml($input, $options);
|
||||
} elseif (!is_string($input)) {
|
||||
throw new XmlException(__d('cake_dev', 'Invalid input.'));
|
||||
}
|
||||
throw new XmlException(__d('cake_dev', 'XML cannot be read.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the input data and create either a SimpleXmlElement object or a DOMDocument.
|
||||
*
|
||||
* @param string $input The input to load.
|
||||
* @param array $options The options to use. See Xml::build()
|
||||
* @return SimpleXmlElement|DOMDocument.
|
||||
*/
|
||||
protected static function _loadXml($input, $options) {
|
||||
$hasDisable = function_exists('libxml_disable_entity_loader');
|
||||
$internalErrors = libxml_use_internal_errors(true);
|
||||
if ($hasDisable && !$options['loadEntities']) {
|
||||
libxml_disable_entity_loader(true);
|
||||
}
|
||||
if ($options['return'] === 'simplexml' || $options['return'] === 'simplexmlelement') {
|
||||
$xml = new SimpleXMLElement($input, LIBXML_NOCDATA);
|
||||
} else {
|
||||
$xml = new DOMDocument();
|
||||
$xml->loadXML($input);
|
||||
}
|
||||
if ($hasDisable && !$options['loadEntities']) {
|
||||
libxml_disable_entity_loader(false);
|
||||
}
|
||||
libxml_use_internal_errors($internalErrors);
|
||||
return $xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform an array into a SimpleXMLElement
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue