From e5c5878b428a1948d05f5a78b209ff5853efc5ac Mon Sep 17 00:00:00 2001 From: Tymoteusz Motylewski Date: Wed, 29 Oct 2014 10:38:57 +0100 Subject: [PATCH] SUPEE-3762 Prevent showing install page after refresing SOAP index Prevents repeated SOAP index page call issue from causing customers to only see the Magento installation page Refreshing the SOAP v2 index page (http://your-magento-host-name/index.php/api/v2_soap/index/) results in all administrators and customers viewing the Magento installation page. --- lib/Zend/Soap/Server.php | 25 +++--- lib/Zend/Xml/Exception.php | 36 ++++++++ lib/Zend/Xml/Security.php | 164 +++++++++++++++++++++++++++++++++++++ 3 files changed, 214 insertions(+), 11 deletions(-) create mode 100644 lib/Zend/Xml/Exception.php create mode 100644 lib/Zend/Xml/Security.php diff --git a/lib/Zend/Soap/Server.php b/lib/Zend/Soap/Server.php index 046cf2357fc..845883668f8 100644 --- a/lib/Zend/Soap/Server.php +++ b/lib/Zend/Soap/Server.php @@ -24,6 +24,12 @@ */ #require_once 'Zend/Server/Interface.php'; +/** @see Zend_Xml_Security */ +#require_once 'Zend/Xml/Security.php'; + +/** @see Zend_Xml_Exception */ +#require_once 'Zend/Xml/Exception.php'; + /** * Zend_Soap_Server * @@ -729,21 +735,18 @@ protected function _setRequest($request) $xml = $request; } - libxml_disable_entity_loader(true); $dom = new DOMDocument(); - if(strlen($xml) == 0 || !$dom->loadXML($xml)) { - #require_once 'Zend/Soap/Server/Exception.php'; - throw new Zend_Soap_Server_Exception('Invalid XML'); - } - foreach ($dom->childNodes as $child) { - if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) { + try { + if(strlen($xml) == 0 || (!$dom = Zend_Xml_Security::scan($xml, $dom))) { #require_once 'Zend/Soap/Server/Exception.php'; - throw new Zend_Soap_Server_Exception( - 'Invalid XML: Detected use of illegal DOCTYPE' - ); + throw new Zend_Soap_Server_Exception('Invalid XML'); } + } catch (Zend_Xml_Exception $e) { + #require_once 'Zend/Soap/Server/Exception.php'; + throw new Zend_Soap_Server_Exception( + $e->getMessage() + ); } - libxml_disable_entity_loader(false); } $this->_request = $xml; return $this; diff --git a/lib/Zend/Xml/Exception.php b/lib/Zend/Xml/Exception.php new file mode 100644 index 00000000000..3418f35dee3 --- /dev/null +++ b/lib/Zend/Xml/Exception.php @@ -0,0 +1,36 @@ + 0) { + return true; + } + return false; + } + + /** + * Scan XML string for potential XXE and XEE attacks + * + * @param string $xml + * @param DomDocument $dom + * @throws Zend_Xml_Exception + * @return SimpleXMLElement|DomDocument|boolean + */ + public static function scan($xml, DOMDocument $dom = null) + { + // If running with PHP-FPM we perform an heuristic scan + // We cannot use libxml_disable_entity_loader because of this bug + // @see https://bugs.php.net/bug.php?id=64938 + if (self::isPhpFpm()) { + self::heuristicScan($xml); + } + + if (null === $dom) { + $simpleXml = true; + $dom = new DOMDocument(); + } + + if (!self::isPhpFpm()) { + $loadEntities = libxml_disable_entity_loader(true); + $useInternalXmlErrors = libxml_use_internal_errors(true); + } + + // Load XML with network access disabled (LIBXML_NONET) + // error disabled with @ for PHP-FPM scenario + set_error_handler(array('Zend_Xml_Security', 'loadXmlErrorHandler'), E_WARNING); + + $result = $dom->loadXml($xml, LIBXML_NONET); + restore_error_handler(); + + if (!$result) { + // Entity load to previous setting + if (!self::isPhpFpm()) { + libxml_disable_entity_loader($loadEntities); + libxml_use_internal_errors($useInternalXmlErrors); + } + return false; + } + + // Scan for potential XEE attacks using ENTITY, if not PHP-FPM + if (!self::isPhpFpm()) { + foreach ($dom->childNodes as $child) { + if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) { + if ($child->entities->length > 0) { + #require_once 'Exception.php'; + throw new Zend_Xml_Exception(self::ENTITY_DETECT); + } + } + } + } + + // Entity load to previous setting + if (!self::isPhpFpm()) { + libxml_disable_entity_loader($loadEntities); + libxml_use_internal_errors($useInternalXmlErrors); + } + + if (isset($simpleXml)) { + $result = simplexml_import_dom($dom); + if (!$result instanceof SimpleXMLElement) { + return false; + } + return $result; + } + return $dom; + } + + /** + * Scan XML file for potential XXE/XEE attacks + * + * @param string $file + * @param DOMDocument $dom + * @throws Zend_Xml_Exception + * @return SimpleXMLElement|DomDocument + */ + public static function scanFile($file, DOMDocument $dom = null) + { + if (!file_exists($file)) { + #require_once 'Exception.php'; + throw new Zend_Xml_Exception( + "The file $file specified doesn't exist" + ); + } + return self::scan(file_get_contents($file), $dom); + } + + /** + * Return true if PHP is running with PHP-FPM + * + * @return boolean + */ + public static function isPhpFpm() + { + if (substr(php_sapi_name(), 0, 3) === 'fpm') { + return true; + } + return false; + } +}