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

Skip to content

Commit ba36fe8

Browse files
[HttpFoundation] Add $trustedHeader arg to Request::setTrustedProxies() - deprecate not setting it
1 parent 3fa8a05 commit ba36fe8

File tree

1 file changed

+90
-63
lines changed

1 file changed

+90
-63
lines changed

src/Symfony/Component/HttpFoundation/Request.php

Lines changed: 90 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,14 @@ class Request
208208
protected static $requestFactory;
209209

210210
private $isHostValid = true;
211-
private $isClientIpsValid = true;
211+
private $isForwardedValid = true;
212+
213+
private static $forwardedParams = array(
214+
self::HEADER_CLIENT_IP => 'for',
215+
self::HEADER_CLIENT_HOST => 'host',
216+
self::HEADER_CLIENT_PROTO => 'proto',
217+
self::HEADER_CLIENT_PORT => 'by',
218+
);
212219

213220
/**
214221
* Constructor.
@@ -548,11 +555,32 @@ public function overrideGlobals()
548555
*
549556
* You should only list the reverse proxies that you manage directly.
550557
*
551-
* @param array $proxies A list of trusted proxies
558+
* @param array $proxies A list of trusted proxies
559+
* @param string $trustedHeader Either Request::HEADER_FORWARDED or Request::HEADER_CLIENT_IP to set which header to trust from your proxies
560+
*
561+
* @throws \InvalidArgumentException When $trustedHeader is invalid
552562
*/
553-
public static function setTrustedProxies(array $proxies)
563+
public static function setTrustedProxies(array $proxies/*, $trustedHeader*/)
554564
{
555565
self::$trustedProxies = $proxies;
566+
567+
if (2 > func_num_args()) {
568+
@trigger_error(sprintf('The %s() method expects Request::HEADER_FORWARDED or Request::HEADER_CLIENT_IP as second argument. Not passing it is deprecated since version 3.3 and will be required in 4.0.', __METHOD__));
569+
570+
return;
571+
}
572+
$trustedHeader = func_get_arg(1);
573+
574+
if (self::HEADER_FORWARDED === $trustedHeader) {
575+
self::$trustedHeaders[self::HEADER_CLIENT_IP] = null;
576+
self::$trustedHeaders[self::HEADER_CLIENT_HOST] = null;
577+
self::$trustedHeaders[self::HEADER_CLIENT_PORT] = null;
578+
self::$trustedHeaders[self::HEADER_CLIENT_PROTO] = null;
579+
} elseif (self::HEADER_CLIENT_IP === $trustedHeader) {
580+
self::$trustedHeaders[self::HEADER_FORWARDED] = null;
581+
} else {
582+
throw new \InvalidArgumentException(sprintf('Invalid trusted header argument: Request::HEADER_FORWARDED or Request::HEADER_CLIENT_IP was expected, "%s" given.', $trustedHeader));
583+
}
556584
}
557585

558586
/**
@@ -797,46 +825,13 @@ public function setSession(SessionInterface $session)
797825
*/
798826
public function getClientIps()
799827
{
800-
$clientIps = array();
801828
$ip = $this->server->get('REMOTE_ADDR');
802829

803830
if (!$this->isFromTrustedProxy()) {
804831
return array($ip);
805832
}
806833

807-
$hasTrustedForwardedHeader = self::$trustedHeaders[self::HEADER_FORWARDED] && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED]);
808-
$hasTrustedClientIpHeader = self::$trustedHeaders[self::HEADER_CLIENT_IP] && $this->headers->has(self::$trustedHeaders[self::HEADER_CLIENT_IP]);
809-
810-
if ($hasTrustedForwardedHeader) {
811-
$forwardedHeader = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]);
812-
preg_match_all('{(for)=("?\[?)([a-z0-9\.:_\-/]*)}', $forwardedHeader, $matches);
813-
$forwardedClientIps = $matches[3];
814-
815-
$forwardedClientIps = $this->normalizeAndFilterClientIps($forwardedClientIps, $ip);
816-
$clientIps = $forwardedClientIps;
817-
}
818-
819-
if ($hasTrustedClientIpHeader) {
820-
$xForwardedForClientIps = array_map('trim', explode(',', $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_IP])));
821-
822-
$xForwardedForClientIps = $this->normalizeAndFilterClientIps($xForwardedForClientIps, $ip);
823-
$clientIps = $xForwardedForClientIps;
824-
}
825-
826-
if ($hasTrustedForwardedHeader && $hasTrustedClientIpHeader && $forwardedClientIps !== $xForwardedForClientIps) {
827-
if (!$this->isClientIpsValid) {
828-
return array('0.0.0.0');
829-
}
830-
$this->isClientIpsValid = false;
831-
832-
throw new ConflictingHeadersException('The request has both a trusted Forwarded header and a trusted Client IP header, conflicting with each other with regards to the originating IP addresses of the request. This is the result of a misconfiguration. You should either configure your proxy only to send one of these headers, or configure your project to distrust one of them.');
833-
}
834-
835-
if (!$hasTrustedForwardedHeader && !$hasTrustedClientIpHeader) {
836-
return $this->normalizeAndFilterClientIps(array(), $ip);
837-
}
838-
839-
return $clientIps;
834+
return $this->getTrustedValues(self::HEADER_CLIENT_IP, $ip) ?: array($ip);
840835
}
841836

842837
/**
@@ -962,31 +957,25 @@ public function getScheme()
962957
*/
963958
public function getPort()
964959
{
965-
if ($this->isFromTrustedProxy()) {
966-
if (self::$trustedHeaders[self::HEADER_CLIENT_PORT] && $port = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_PORT])) {
967-
return $port;
968-
}
969-
970-
if (self::$trustedHeaders[self::HEADER_CLIENT_PROTO] && 'https' === $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_PROTO], 'http')) {
971-
return 443;
972-
}
960+
if ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_CLIENT_PORT)) {
961+
$host = $host[0];
962+
} elseif ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_CLIENT_HOST)) {
963+
$host = $host[0];
964+
} elseif (!$host = $this->headers->get('HOST')) {
965+
return $this->server->get('SERVER_PORT');
973966
}
974967

975-
if ($host = $this->headers->get('HOST')) {
976-
if ($host[0] === '[') {
977-
$pos = strpos($host, ':', strrpos($host, ']'));
978-
} else {
979-
$pos = strrpos($host, ':');
980-
}
981-
982-
if (false !== $pos) {
983-
return (int) substr($host, $pos + 1);
984-
}
968+
if ($host[0] === '[') {
969+
$pos = strpos($host, ':', strrpos($host, ']'));
970+
} else {
971+
$pos = strrpos($host, ':');
972+
}
985973

986-
return 'https' === $this->getScheme() ? 443 : 80;
974+
if (false !== $pos) {
975+
return (int) substr($host, $pos + 1);
987976
}
988977

989-
return $this->server->get('SERVER_PORT');
978+
return 'https' === $this->getScheme() ? 443 : 80;
990979
}
991980

992981
/**
@@ -1186,8 +1175,8 @@ public function getQueryString()
11861175
*/
11871176
public function isSecure()
11881177
{
1189-
if ($this->isFromTrustedProxy() && self::$trustedHeaders[self::HEADER_CLIENT_PROTO] && $proto = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_PROTO])) {
1190-
return in_array(strtolower(current(explode(',', $proto))), array('https', 'on', 'ssl', '1'));
1178+
if ($this->isFromTrustedProxy() && $proto = $this->getTrustedValues(self::HEADER_CLIENT_PROTO)) {
1179+
return in_array(strtolower($proto[0]), array('https', 'on', 'ssl', '1'), true);
11911180
}
11921181

11931182
$https = $this->server->get('HTTPS');
@@ -1212,10 +1201,8 @@ public function isSecure()
12121201
*/
12131202
public function getHost()
12141203
{
1215-
if ($this->isFromTrustedProxy() && self::$trustedHeaders[self::HEADER_CLIENT_HOST] && $host = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_HOST])) {
1216-
$elements = explode(',', $host);
1217-
1218-
$host = $elements[count($elements) - 1];
1204+
if ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_CLIENT_HOST)) {
1205+
$host = end($host);
12191206
} elseif (!$host = $this->headers->get('HOST')) {
12201207
if (!$host = $this->server->get('SERVER_NAME')) {
12211208
$host = $this->server->get('SERVER_ADDR', '');
@@ -1998,6 +1985,9 @@ public function isFromTrustedProxy()
19981985

19991986
private function normalizeAndFilterClientIps(array $clientIps, $ip)
20001987
{
1988+
if (!$clientIps) {
1989+
return array();
1990+
}
20011991
$clientIps[] = $ip; // Complete the IP chain with the IP the request actually came from
20021992
$firstTrustedIp = null;
20031993

@@ -2026,4 +2016,41 @@ private function normalizeAndFilterClientIps(array $clientIps, $ip)
20262016
// Now the IP chain contains only untrusted proxies and the client IP
20272017
return $clientIps ? array_reverse($clientIps) : array($firstTrustedIp);
20282018
}
2019+
2020+
private function getTrustedValues($type, $ip = null)
2021+
{
2022+
$clientValues = array();
2023+
$forwardedValues = array();
2024+
2025+
if (self::$trustedHeaders[$type] && $this->headers->has(self::$trustedHeaders[$type])) {
2026+
foreach (explode(',', $this->headers->get(self::$trustedHeaders[$type])) as $v) {
2027+
$clientValues[] = (self::HEADER_CLIENT_PORT === $type ? '0.0.0.0:' : '').trim($v);
2028+
}
2029+
}
2030+
2031+
if (self::$trustedHeaders[self::HEADER_FORWARDED] && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED])) {
2032+
$forwardedValues = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]);
2033+
$forwardedValues = preg_match_all(sprintf('{(?:%s)=(?:"?\[?)([a-zA-Z0-9\.:_\-/]*+)}', self::$forwardedParams[$type]), $forwardedValues, $matches) ? $matches[1] : array('');
2034+
}
2035+
2036+
if (null !== $ip) {
2037+
$clientValues = $this->normalizeAndFilterClientIps($clientValues, $ip);
2038+
$forwardedValues = $this->normalizeAndFilterClientIps($forwardedValues, $ip);
2039+
}
2040+
2041+
if ($forwardedValues === $clientValues || !$clientValues) {
2042+
return $forwardedValues;
2043+
}
2044+
2045+
if (!$forwardedValues) {
2046+
return $clientValues;
2047+
}
2048+
2049+
if (!$this->isForwardedValid) {
2050+
return null !== $ip ? array('0.0.0.0', $ip) : array();
2051+
}
2052+
$this->isForwardedValid = false;
2053+
2054+
throw new ConflictingHeadersException(sprintf('The request has both a trusted "%s" header and a trusted "%s" header, conflicting with each other. You should either configure your proxy to remove the "%2$s" header, or configure your project to distrust it.', self::$trustedHeaders[self::HEADER_FORWARDED], self::$trustedHeaders[$type]));
2055+
}
20292056
}

0 commit comments

Comments
 (0)