Browse Source

[Serializer] Fix XML decoding attack vector through external entities

Jordi Boggiano 13 năm trước cách đây
mục cha
commit
3e64d36cbd

+ 11 - 0
src/Symfony/Component/Serializer/Encoder/XmlEncoder.php

@@ -54,7 +54,18 @@ class XmlEncoder extends SerializerAwareEncoder implements EncoderInterface, Dec
      */
     public function decode($data, $format)
     {
+        $internalErrors = libxml_use_internal_errors(true);
+        $disableEntities = libxml_disable_entity_loader(true);
+        libxml_clear_errors();
+
         $xml = simplexml_load_string($data);
+        libxml_use_internal_errors($internalErrors);
+        libxml_disable_entity_loader($disableEntities);
+
+        if ($error = libxml_get_last_error()) {
+            throw new UnexpectedValueException($error->message);
+        }
+
         if (!$xml->count()) {
             if (!$xml->attributes()) {
                 return (string) $xml;

+ 18 - 0
tests/Symfony/Tests/Component/Serializer/Encoder/XmlEncoderTest.php

@@ -9,6 +9,7 @@ use Symfony\Tests\Component\Serializer\Fixtures\Dummy;
 use Symfony\Tests\Component\Serializer\Fixtures\ScalarDummy;
 use Symfony\Component\Serializer\Encoder\XmlEncoder;
 use Symfony\Component\Serializer\Serializer;
+use Symfony\Component\Serializer\Exception\UnexpectedValueException;
 use Symfony\Component\Serializer\Normalizer\CustomNormalizer;
 
 /*
@@ -232,6 +233,23 @@ class XmlEncoderTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals($expected, $this->encoder->decode($source, 'xml'));
     }
 
+    /**
+     * @expectedException Symfony\Component\Serializer\Exception\UnexpectedValueException
+     */
+    public function testPreventsComplexExternalEntities()
+    {
+        $oldCwd = getcwd();
+        chdir(__DIR__);
+
+        try {
+            $decoded = $this->encoder->decode('<?xml version="1.0"?><!DOCTYPE scan[<!ENTITY test SYSTEM "php://filter/read=convert.base64-encode/resource=XmlEncoderTest.php">]><scan>&test;</scan>', 'xml');
+            chdir($oldCwd);
+        } catch (UnexpectedValueException $e) {
+            chdir($oldCwd);
+            throw $e;
+        }
+    }
+
     protected function getXmlSource()
     {
         return '<?xml version="1.0"?>'."\n".