Merge branch '2.0' into 2.1
* 2.0: added trusted hosts check Conflicts: src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php src/Symfony/Component/HttpFoundation/Tests/RequestTest.php
This commit is contained in:
commit
31f0efd7bc
@ -78,6 +78,13 @@ class Configuration implements ConfigurationInterface
|
|||||||
->scalarNode('ide')->defaultNull()->end()
|
->scalarNode('ide')->defaultNull()->end()
|
||||||
->booleanNode('test')->end()
|
->booleanNode('test')->end()
|
||||||
->scalarNode('default_locale')->defaultValue('en')->end()
|
->scalarNode('default_locale')->defaultValue('en')->end()
|
||||||
|
->arrayNode('trusted_hosts')
|
||||||
|
->beforeNormalization()
|
||||||
|
->ifTrue(function($v) { return is_string($v); })
|
||||||
|
->then(function($v) { return array($v); })
|
||||||
|
->end()
|
||||||
|
->prototype('scalar')->end()
|
||||||
|
->end()
|
||||||
->end()
|
->end()
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -62,6 +62,7 @@ class FrameworkExtension extends Extension
|
|||||||
$container->setParameter('kernel.secret', $config['secret']);
|
$container->setParameter('kernel.secret', $config['secret']);
|
||||||
|
|
||||||
$container->setParameter('kernel.trusted_proxies', $config['trusted_proxies']);
|
$container->setParameter('kernel.trusted_proxies', $config['trusted_proxies']);
|
||||||
|
$container->setParameter('kernel.trusted_hosts', $config['trusted_hosts']);
|
||||||
|
|
||||||
// @deprecated, to be removed in 2.3
|
// @deprecated, to be removed in 2.3
|
||||||
$container->setParameter('kernel.trust_proxy_headers', $config['trust_proxy_headers']);
|
$container->setParameter('kernel.trust_proxy_headers', $config['trust_proxy_headers']);
|
||||||
|
@ -45,6 +45,10 @@ class FrameworkBundle extends Bundle
|
|||||||
} elseif ($this->container->getParameter('kernel.trust_proxy_headers')) {
|
} elseif ($this->container->getParameter('kernel.trust_proxy_headers')) {
|
||||||
Request::trustProxyData(); // @deprecated, to be removed in 2.3
|
Request::trustProxyData(); // @deprecated, to be removed in 2.3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($trustedHosts = $this->container->getParameter('kernel.trusted_hosts')) {
|
||||||
|
Request::setTrustedHosts($trustedHosts);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function build(ContainerBuilder $container)
|
public function build(ContainerBuilder $container)
|
||||||
|
@ -31,7 +31,7 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
|
|||||||
public function getTestConfigTreeData()
|
public function getTestConfigTreeData()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
array(array('secret' => 's3cr3t'), array('secret' => 's3cr3t', 'trusted_proxies' => array(), 'trust_proxy_headers' => false, 'ide' => NULL, 'annotations' => array('cache' => 'file', 'file_cache_dir' => '%kernel.cache_dir%/annotations', 'debug' => false), 'default_locale' => 'en', 'charset' => null)),
|
array(array('secret' => 's3cr3t'), array('secret' => 's3cr3t', 'trusted_proxies' => array(), 'trusted_hosts' => array(), 'trust_proxy_headers' => false, 'ide' => NULL, 'annotations' => array('cache' => 'file', 'file_cache_dir' => '%kernel.cache_dir%/annotations', 'debug' => false), 'default_locale' => 'en', 'charset' => null)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,12 +50,12 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
|
|||||||
public function getTestValidTrustedProxiesData()
|
public function getTestValidTrustedProxiesData()
|
||||||
{
|
{
|
||||||
return array(
|
return array(
|
||||||
array(array('secret' => 's3cr3t', 'trusted_proxies' => array('127.0.0.1')), array('secret' => 's3cr3t', 'trusted_proxies' => array('127.0.0.1'), 'trust_proxy_headers' => false, 'ide' => NULL, 'annotations' => array('cache' => 'file', 'file_cache_dir' => '%kernel.cache_dir%/annotations', 'debug' => false), 'default_locale' => 'en', 'charset' => null)),
|
array(array('secret' => 's3cr3t', 'trusted_proxies' => array('127.0.0.1')), array('secret' => 's3cr3t', 'trusted_hosts' => array(), 'trusted_proxies' => array('127.0.0.1'), 'trust_proxy_headers' => false, 'ide' => NULL, 'annotations' => array('cache' => 'file', 'file_cache_dir' => '%kernel.cache_dir%/annotations', 'debug' => false), 'default_locale' => 'en', 'charset' => null)),
|
||||||
array(array('secret' => 's3cr3t', 'trusted_proxies' => array('::1')), array('secret' => 's3cr3t', 'trusted_proxies' => array('::1'), 'trust_proxy_headers' => false, 'ide' => NULL, 'annotations' => array('cache' => 'file', 'file_cache_dir' => '%kernel.cache_dir%/annotations', 'debug' => false), 'default_locale' => 'en', 'charset' => null)),
|
array(array('secret' => 's3cr3t', 'trusted_proxies' => array('::1')), array('secret' => 's3cr3t', 'trusted_hosts' => array(), 'trusted_proxies' => array('::1'), 'trust_proxy_headers' => false, 'ide' => NULL, 'annotations' => array('cache' => 'file', 'file_cache_dir' => '%kernel.cache_dir%/annotations', 'debug' => false), 'default_locale' => 'en', 'charset' => null)),
|
||||||
array(array('secret' => 's3cr3t', 'trusted_proxies' => array('127.0.0.1', '::1')), array('secret' => 's3cr3t', 'trusted_proxies' => array('127.0.0.1', '::1'), 'trust_proxy_headers' => false, 'ide' => NULL, 'annotations' => array('cache' => 'file', 'file_cache_dir' => '%kernel.cache_dir%/annotations', 'debug' => false), 'default_locale' => 'en', 'charset' => null)),
|
array(array('secret' => 's3cr3t', 'trusted_proxies' => array('127.0.0.1', '::1')), array('secret' => 's3cr3t', 'trusted_hosts' => array(), 'trusted_proxies' => array('127.0.0.1', '::1'), 'trust_proxy_headers' => false, 'ide' => NULL, 'annotations' => array('cache' => 'file', 'file_cache_dir' => '%kernel.cache_dir%/annotations', 'debug' => false), 'default_locale' => 'en', 'charset' => null)),
|
||||||
array(array('secret' => 's3cr3t', 'trusted_proxies' => null), array('secret' => 's3cr3t', 'trusted_proxies' => array(), 'trust_proxy_headers' => false, 'ide' => NULL, 'annotations' => array('cache' => 'file', 'file_cache_dir' => '%kernel.cache_dir%/annotations', 'debug' => false), 'default_locale' => 'en', 'charset' => null)),
|
array(array('secret' => 's3cr3t', 'trusted_proxies' => null), array('secret' => 's3cr3t', 'trusted_hosts' => array(), 'trusted_proxies' => array(), 'trust_proxy_headers' => false, 'ide' => NULL, 'annotations' => array('cache' => 'file', 'file_cache_dir' => '%kernel.cache_dir%/annotations', 'debug' => false), 'default_locale' => 'en', 'charset' => null)),
|
||||||
array(array('secret' => 's3cr3t', 'trusted_proxies' => false), array('secret' => 's3cr3t', 'trusted_proxies' => array(), 'trust_proxy_headers' => false, 'ide' => NULL, 'annotations' => array('cache' => 'file', 'file_cache_dir' => '%kernel.cache_dir%/annotations', 'debug' => false), 'default_locale' => 'en', 'charset' => null)),
|
array(array('secret' => 's3cr3t', 'trusted_proxies' => false), array('secret' => 's3cr3t', 'trusted_hosts' => array(), 'trusted_proxies' => array(), 'trust_proxy_headers' => false, 'ide' => NULL, 'annotations' => array('cache' => 'file', 'file_cache_dir' => '%kernel.cache_dir%/annotations', 'debug' => false), 'default_locale' => 'en', 'charset' => null)),
|
||||||
array(array('secret' => 's3cr3t', 'trusted_proxies' => array()), array('secret' => 's3cr3t', 'trusted_proxies' => array(), 'trust_proxy_headers' => false, 'ide' => NULL, 'annotations' => array('cache' => 'file', 'file_cache_dir' => '%kernel.cache_dir%/annotations', 'debug' => false), 'default_locale' => 'en', 'charset' => null)),
|
array(array('secret' => 's3cr3t', 'trusted_proxies' => array()), array('secret' => 's3cr3t', 'trusted_hosts' => array(), 'trusted_proxies' => array(), 'trust_proxy_headers' => false, 'ide' => NULL, 'annotations' => array('cache' => 'file', 'file_cache_dir' => '%kernel.cache_dir%/annotations', 'debug' => false), 'default_locale' => 'en', 'charset' => null)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +39,16 @@ class Request
|
|||||||
|
|
||||||
protected static $trustedProxies = array();
|
protected static $trustedProxies = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
protected static $trustedHostPatterns = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
protected static $trustedHosts = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Names for headers that can be trusted when
|
* Names for headers that can be trusted when
|
||||||
* using trusted proxies.
|
* using trusted proxies.
|
||||||
@ -482,6 +492,32 @@ class Request
|
|||||||
self::$trustProxy = $proxies ? true : false;
|
self::$trustProxy = $proxies ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a list of trusted host patterns.
|
||||||
|
*
|
||||||
|
* You should only list the hosts you manage using regexs.
|
||||||
|
*
|
||||||
|
* @param array $hostPatterns A list of trusted host patterns
|
||||||
|
*/
|
||||||
|
public static function setTrustedHosts(array $hostPatterns)
|
||||||
|
{
|
||||||
|
self::$trustedHostPatterns = array_map(function ($hostPattern) {
|
||||||
|
return sprintf('{%s}i', str_replace('}', '\\}', $hostPattern));
|
||||||
|
}, $hostPatterns);
|
||||||
|
// we need to reset trusted hosts on trusted host patterns change
|
||||||
|
self::$trustedHosts = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the list of trusted host patterns.
|
||||||
|
*
|
||||||
|
* @return array An array of trusted host patterns.
|
||||||
|
*/
|
||||||
|
public static function getTrustedHosts()
|
||||||
|
{
|
||||||
|
return self::$trustedHostPatterns;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the name for trusted headers.
|
* Sets the name for trusted headers.
|
||||||
*
|
*
|
||||||
@ -1007,6 +1043,24 @@ class Request
|
|||||||
throw new \UnexpectedValueException('Invalid Host');
|
throw new \UnexpectedValueException('Invalid Host');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (count(self::$trustedHostPatterns) > 0) {
|
||||||
|
// to avoid host header injection attacks, you should provide a list of trusted host patterns
|
||||||
|
|
||||||
|
if (in_array($host, self::$trustedHosts)) {
|
||||||
|
return $host;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (self::$trustedHostPatterns as $pattern) {
|
||||||
|
if (preg_match($pattern, $host)) {
|
||||||
|
self::$trustedHosts[] = $host;
|
||||||
|
|
||||||
|
return $host;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \UnexpectedValueException('Untrusted Host');
|
||||||
|
}
|
||||||
|
|
||||||
return $host;
|
return $host;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1358,6 +1358,37 @@ class RequestTest extends \PHPUnit_Framework_TestCase
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testTrustedHosts()
|
||||||
|
{
|
||||||
|
// create a request
|
||||||
|
$request = Request::create('/');
|
||||||
|
|
||||||
|
// no trusted host set -> no host check
|
||||||
|
$request->headers->set('host', 'evil.com');
|
||||||
|
$this->assertEquals('evil.com', $request->getHost());
|
||||||
|
|
||||||
|
// add a trusted domain and all its subdomains
|
||||||
|
Request::setTrustedHosts(array('.*\.?trusted.com$'));
|
||||||
|
|
||||||
|
// untrusted host
|
||||||
|
$request->headers->set('host', 'evil.com');
|
||||||
|
try {
|
||||||
|
$request->getHost();
|
||||||
|
$this->fail('Request::getHost() should throw an exception when host is not trusted.');
|
||||||
|
} catch (\UnexpectedValueException $e) {
|
||||||
|
$this->assertEquals('Untrusted Host', $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// trusted hosts
|
||||||
|
$request->headers->set('host', 'trusted.com');
|
||||||
|
$this->assertEquals('trusted.com', $request->getHost());
|
||||||
|
$request->headers->set('host', 'subdomain.trusted.com');
|
||||||
|
$this->assertEquals('subdomain.trusted.com', $request->getHost());
|
||||||
|
|
||||||
|
// reset request for following tests
|
||||||
|
Request::setTrustedHosts(array());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RequestContentProxy extends Request
|
class RequestContentProxy extends Request
|
||||||
|
Reference in New Issue
Block a user