From c8836a008d1426a03c2260efaf42967756824618 Mon Sep 17 00:00:00 2001 From: Benjamin Eberlei Date: Sun, 23 Mar 2014 09:58:31 +0100 Subject: [PATCH] [DDC-3045] Check that EntityRepository APIs prevent SQL injection through field names. Improve EntityManager#find() error handling when invalid identifier fields are passed. --- lib/Doctrine/ORM/EntityManager.php | 5 ++ lib/Doctrine/ORM/ORMException.php | 14 ++++++ .../ORM/Functional/EntityRepositoryTest.php | 46 +++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/lib/Doctrine/ORM/EntityManager.php b/lib/Doctrine/ORM/EntityManager.php index 08f780af9..0c1b16b5c 100644 --- a/lib/Doctrine/ORM/EntityManager.php +++ b/lib/Doctrine/ORM/EntityManager.php @@ -397,6 +397,11 @@ use Doctrine\Common\Util\ClassUtils; } $sortedId[$identifier] = $id[$identifier]; + unset($id[$identifier]); + } + + if ($id) { + throw ORMException::unrecognizedIdentifierFields($class->name, array_keys($id)); } $unitOfWork = $this->getUnitOfWork(); diff --git a/lib/Doctrine/ORM/ORMException.php b/lib/Doctrine/ORM/ORMException.php index b9a0b9cec..40c0cb3be 100644 --- a/lib/Doctrine/ORM/ORMException.php +++ b/lib/Doctrine/ORM/ORMException.php @@ -283,6 +283,20 @@ class ORMException extends Exception return new self("The identifier $fieldName is missing for a query of " . $className); } + /** + * @param string $className + * @param string $fieldName + * + * @return ORMException + */ + public static function unrecognizedIdentifierFields($className, $fieldNames) + { + return new self( + "Unrecognized identifier fields: '" . implode("', '", $fieldNames) . "' " . + "are not present on class '" . $className . "'." + ); + } + /** * @param string $functionName * diff --git a/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php b/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php index 6432c3072..502eda0ec 100644 --- a/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/EntityRepositoryTest.php @@ -882,5 +882,51 @@ class EntityRepositoryTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertInstanceOf('Doctrine\ORM\Query\ResultSetMappingBuilder', $rsm); $this->assertEquals(array('u' => 'Doctrine\Tests\Models\CMS\CmsUser'), $rsm->aliasMap); } + + /** + * @group DDC-3045 + */ + public function testFindByFieldInjectionPrevented() + { + $this->setExpectedException('Doctrine\ORM\ORMException', 'Unrecognized field: '); + + $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + $repository->findBy(array('username = ?; DELETE FROM cms_users; SELECT 1 WHERE 1' => 'test')); + } + + /** + * @group DDC-3045 + */ + public function testFindOneByFieldInjectionPrevented() + { + $this->setExpectedException('Doctrine\ORM\ORMException', 'Unrecognized field: '); + + $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + $repository->findOneBy(array('username = ?; DELETE FROM cms_users; SELECT 1 WHERE 1' => 'test')); + } + + /** + * @group DDC-3045 + */ + public function testMatchingInjectionPrevented() + { + $this->setExpectedException('Doctrine\ORM\ORMException', 'Unrecognized field: '); + + $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + $repository->matching(new Criteria( + Criteria::expr()->eq('username = ?; DELETE FROM cms_users; SELECT 1 WHERE 1', 'beberlei') + )); + } + + /** + * @group DDC-3045 + */ + public function testFindInjectionPrevented() + { + $this->setExpectedException('Doctrine\ORM\ORMException', 'Unrecognized identifier fields: '); + + $repository = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser'); + $repository->find(array('username = ?; DELETE FROM cms_users; SELECT 1 WHERE 1' => 'test', 'id' => 1)); + } }