Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c35cc5b

Browse files
jfsimonfabpot
authored andcommitted
added trusted hosts check
1 parent 6d555bc commit c35cc5b

File tree

6 files changed

+104
-7
lines changed

6 files changed

+104
-7
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,13 @@ public function getConfigTreeBuilder()
6363
->scalarNode('secret')->isRequired()->end()
6464
->scalarNode('ide')->defaultNull()->end()
6565
->booleanNode('test')->end()
66+
->arrayNode('trusted_hosts')
67+
->beforeNormalization()
68+
->ifTrue(function($v) { return is_string($v); })
69+
->then(function($v) { return array($v); })
70+
->end()
71+
->prototype('scalar')->end()
72+
->end()
6673
->end()
6774
;
6875

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ public function load(array $configs, ContainerBuilder $container)
6363
$container->setParameter('kernel.secret', $config['secret']);
6464

6565
$container->setParameter('kernel.trusted_proxies', $config['trusted_proxies']);
66+
$container->setParameter('kernel.trusted_hosts', $config['trusted_hosts']);
6667

6768
// @deprecated, to be removed in 2.3
6869
$container->setParameter('kernel.trust_proxy_headers', $config['trust_proxy_headers']);

src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ public function boot()
4242
} elseif ($this->container->getParameter('kernel.trust_proxy_headers')) {
4343
Request::trustProxyData(); // @deprecated, to be removed in 2.3
4444
}
45+
46+
if ($trustedHosts = $this->container->getParameter('kernel.trusted_hosts')) {
47+
Request::setTrustedHosts($trustedHosts);
48+
}
4549
}
4650

4751
public function build(ContainerBuilder $container)

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/ConfigurationTest.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public function testConfigTree($options, $results)
3131
public function getTestConfigTreeData()
3232
{
3333
return array(
34-
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))),
34+
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))),
3535
);
3636
}
3737

@@ -50,12 +50,12 @@ public function testValidTrustedProxies($options, $results)
5050
public function getTestValidTrustedProxiesData()
5151
{
5252
return array(
53-
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))),
54-
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))),
55-
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))),
56-
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))),
57-
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))),
58-
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))),
53+
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))),
54+
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))),
55+
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))),
56+
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))),
57+
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))),
58+
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))),
5959
);
6060
}
6161

src/Symfony/Component/HttpFoundation/Request.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@ class Request
2929

3030
protected static $trustedProxies = array();
3131

32+
/**
33+
* @var string[]
34+
*/
35+
protected static $trustedHostPatterns = array();
36+
37+
/**
38+
* @var string[]
39+
*/
40+
protected static $trustedHosts = array();
41+
3242
/**
3343
* Names for headers that can be trusted when
3444
* using trusted proxies.
@@ -400,6 +410,32 @@ public static function setTrustedProxies(array $proxies)
400410
self::$trustProxy = $proxies ? true : false;
401411
}
402412

413+
/**
414+
* Sets a list of trusted host patterns.
415+
*
416+
* You should only list the hosts you manage using regexs.
417+
*
418+
* @param array $hostPatterns A list of trusted host patterns
419+
*/
420+
public static function setTrustedHosts(array $hostPatterns)
421+
{
422+
self::$trustedHostPatterns = array_map(function ($hostPattern) {
423+
return sprintf('{%s}i', str_replace('}', '\\}', $hostPattern));
424+
}, $hostPatterns);
425+
// we need to reset trusted hosts on trusted host patterns change
426+
self::$trustedHosts = array();
427+
}
428+
429+
/**
430+
* Gets the list of trusted host patterns.
431+
*
432+
* @return array An array of trusted host patterns.
433+
*/
434+
public static function getTrustedHosts()
435+
{
436+
return self::$trustedHostPatterns;
437+
}
438+
403439
/**
404440
* Sets the name for trusted headers.
405441
*
@@ -821,6 +857,24 @@ public function getHost()
821857
throw new \UnexpectedValueException('Invalid Host');
822858
}
823859

860+
if (count(self::$trustedHostPatterns) > 0) {
861+
// to avoid host header injection attacks, you should provide a list of trusted host patterns
862+
863+
if (in_array($host, self::$trustedHosts)) {
864+
return $host;
865+
}
866+
867+
foreach (self::$trustedHostPatterns as $pattern) {
868+
if (preg_match($pattern, $host)) {
869+
self::$trustedHosts[] = $host;
870+
871+
return $host;
872+
}
873+
}
874+
875+
throw new \UnexpectedValueException('Untrusted Host');
876+
}
877+
824878
return $host;
825879
}
826880

tests/Symfony/Tests/Component/HttpFoundation/RequestTest.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,37 @@ public function testTrustedProxies()
917917
// reset
918918
Request::setTrustedProxies(array());
919919
}
920+
921+
public function testTrustedHosts()
922+
{
923+
// create a request
924+
$request = Request::create('/');
925+
926+
// no trusted host set -> no host check
927+
$request->headers->set('host', 'evil.com');
928+
$this->assertEquals('evil.com', $request->getHost());
929+
930+
// add a trusted domain and all its subdomains
931+
Request::setTrustedHosts(array('.*\.?trusted.com$'));
932+
933+
// untrusted host
934+
$request->headers->set('host', 'evil.com');
935+
try {
936+
$request->getHost();
937+
$this->fail('Request::getHost() should throw an exception when host is not trusted.');
938+
} catch (\UnexpectedValueException $e) {
939+
$this->assertEquals('Untrusted Host', $e->getMessage());
940+
}
941+
942+
// trusted hosts
943+
$request->headers->set('host', 'trusted.com');
944+
$this->assertEquals('trusted.com', $request->getHost());
945+
$request->headers->set('host', 'subdomain.trusted.com');
946+
$this->assertEquals('subdomain.trusted.com', $request->getHost());
947+
948+
// reset request for following tests
949+
Request::setTrustedHosts(array());
950+
}
920951
}
921952

922953
class RequestContentProxy extends Request

0 commit comments

Comments
 (0)