8000 Merge branch '2.0' into 2.1 · symfony/symfony@6c67476 · GitHub
[go: up one dir, main page]

Skip to content
8000

Commit 6c67476

Browse files
committed
Merge branch '2.0' into 2.1
* 2.0: replaced magic strings by proper constants refactored tests for Request fixed the logic in Request::isSecure() (if the information comes from a source that we trust, don't check other ones) added a way to configure the X-Forwarded-XXX header names and a way to disable trusting them fixed algorithm used to determine the trusted client IP removed the non-standard Client-IP HTTP header Conflicts: src/Symfony/Component/HttpFoundation/Request.php src/Symfony/Component/HttpFoundation/Tests/RequestTest.php
2 parents 922c201 + e5536f0 commit 6c67476

File tree

2 files changed

+207
-91
lines changed

2 files changed

+207
-91
lines changed

src/Symfony/Component/HttpFoundation/Request.php

Lines changed: 122 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,28 @@
3030
*/
3131
class Request
3232
{
33-
protected static $trustProxy = false;
33+
const HEADER_CLIENT_IP = 'client_ip';
34+
const HEADER_CLIENT_HOST = 'client_host';
35+
const HEADER_CLIENT_PROTO = 'client_proto';
36+
const HEADER_CLIENT_PORT = 'client_port';
37+
38+
protected static $trustProxyData = false;
39+
40+
protected static $trustedProxies = array();
41+
42+
/**
43+
* Names for headers that can be trusted when
44+
* using trusted proxies.
45+
*
46+
* The default names are non-standard, but widely used
47+
* by popular reverse proxies (like Apache mod_proxy or Amazon EC2).
48+
*/
49+
protected static $trustedHeaders = array(
50+
self::HEADER_CLIENT_IP => 'X_FORWARDED_FOR',
51+
self::HEADER_CLIENT_HOST => 'X_FORWARDED_HOST',
52+
self::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO',
53+
self::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT',
54+
);
3455

3556
/**
3657
* @var \Symfony\Component\HttpFoundation\ParameterBag
@@ -439,14 +460,50 @@ public function overrideGlobals()
439460
/**
440461
* Trusts $_SERVER entries coming from proxies.
441462
*
442-
* You should only call this method if your application
443-
* is hosted behind a reverse proxy that you manage.
463+
* @deprecated Deprecated since version 2.0, to be removed in 2.3. Use setTrustedProxies instead.
464+
*/
465+
public static function trustProxyData()
466+
{
467+
self::$trustProxyData = true;
468+
}
469+
470+
/**
471+
* Sets a list of trusted proxies.
472+
*
473+
* You should only list the reverse proxies that you manage directly.
474+
*
475+
* @param array $proxies A list of trusted proxies
444476
*
445477
* @api
446478
*/
447-
public static function trustProxyData()
479+
public static function setTrustedProxies(array $proxies)
448480
{
449-
self::$trustProxy = true;
481+
self::$trustedProxies = $proxies;
482+
self::$trustProxyData = $proxies ? true : false;
483+
}
484+
485+
/**
486+
* Sets the name for trusted headers.
487+
*
488+
* The following header keys are supported:
489+
*
490+
* * Request::HEADER_CLIENT_IP: defaults to X-Forwarded-For (see getClientIp())
491+
* * Request::HEADER_CLIENT_HOST: defaults to X-Forwarded-Host (see getClientHost())
492+
* * Request::HEADER_CLIENT_PORT: defaults to X-Forwarded-Port (see getClientPort())
493+
* * Request::HEADER_CLIENT_PROTO: defaults to X-Forwarded-Proto (see getScheme() and isSecure())
494+
*
495+
* Setting an empty value allows to disable the trusted header for the given key.
496+
*
497+
* @param string $key The header key
498+
* @param string $value The header name
499+
*/
500+
public static function setTrustedHeaderName($key, $value)
501+
{
502+
if (!array_key_exists($key, self::$trustedHeaders)) {
503+
throw new \InvalidArgumentException(sprintf('Unable to set the trusted header name for key "%s".', $key));
504+
}
505+
506+
self::$trustedHeaders[$key] = $value;
450507
}
451508

452509
/**
@@ -582,31 +639,43 @@ public function setSession(SessionInterface $session)
582639
/**
583640
* Returns the client IP address.
584641
*
642+
* This method can read the client IP address from the "X-Forwarded-For" header
643+
* when trusted proxies were set via "setTrustedProxies()". The "X-Forwarded-For"
644+
* header value is a comma+space separated list of IP addresses, the left-most
645+
* being the original client, and each successive proxy that passed the request
646+
* adding the IP address where it received the request from.
647+
*
648+
* If your reverse proxy uses a different header name than "X-Forwarded-For",
649+
* ("Client-Ip" for instance), configure it via "setTrustedHeaderName()" with
650+
* the "client-ip" key.
651+
*
585652
* @return string The client IP address
586653
*
654+
* @see http://en.wikipedia.org/wiki/X-Forwarded-For
655+
*
656+
* @deprecated The proxy argument is deprecated since version 2.0 and will be removed in 2.3. Use setTrustedProxies instead.
657+
*
587658
* @api
588659
*/
589660
public function getClientIp()
590661
{
591-
if (self::$trustProxy) {
592-
if ($this->server->has('HTTP_CLIENT_IP')) {
593-
return $this->server->get('HTTP_CLIENT_IP');
594-
} elseif ($this->server->has('HTTP_X_FORWARDED_FOR')) {
595-
$clientIp = explode(',', $this->server->get('HTTP_X_FORWARDED_FOR'));
596-
597-
foreach ($clientIp as $ipAddress) {
598-
$cleanIpAddress = trim($ipAddress);
662+
$ip = $this->server->get('REMOTE_ADDR');
599663

600-
if (false !== filter_var($cleanIpAddress, FILTER_VALIDATE_IP)) {
601-
return $cleanIpAddress;
602-
}
603-
}
664+
if (!self::$trustProxyData) {
665+
return $ip;
666+
}
604667

605-
return '';
606-
}
668+
if (!self::$trustedHeaders[self::HEADER_CLIENT_IP] || !$this->headers->has(self::$trustedHeaders[self::HEADER_CLIENT_IP])) {
669+
return $ip;
607670
}
608671

609-
return $this->server->get('REMOTE_ADDR');
672+
$clientIps = array_map('trim', explode(',', $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_IP])));
673+
$clientIps[] = $ip;
674+
675+
$trustedProxies = self::$trustProxyData && !self::$trustedProxies ? array($ip) : self::$trustedProxies;
676+
$clientIps = array_diff($clientIps, $trustedProxies);
677+
678+
return array_pop($clientIps);
610679
}
611680

612681
/**
@@ -705,14 +774,22 @@ public function getScheme()
705774
/**
706775
* Returns the port on which the request is made.
707776
*
777+
* This method can read the client port from the "X-Forwarded-Port" header
778+
* when trusted proxies were set via "setTrustedProxies()".
779+
*
780+
* The "X-Forwarded-Port" header must contain the client port.
781+
*
782+
* If your reverse proxy uses a different header name than "X-Forwarded-Port",
783+
* configure it via "setTrustedHeaderName()" with the "client-port" key.
784+
*
708785
* @return string
709786
*
710787
* @api
711788
*/
712789
public function getPort()
713790
{
714-
if (self::$trustProxy && $this->headers->has('X-Forwarded-Port')) {
715-
return $this->headers->get('X-Forwarded-Port');
791+
if (self::$trustProxyData && self::$trustedHeaders[self::HEADER_CLIENT_PORT] && $port = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_PORT])) {
792+
return $port;
716793
}
717794

718795
return $this->server->get('SERVER_PORT');
@@ -858,31 +935,46 @@ public function getQueryString()
858935
/**
859936
* Checks whether the request is secure or not.
860937
*
938+
* This method can read the client port from the "X-Forwarded-Proto" header
939+
* when trusted proxies were set via "setTrustedProxies()".
940+
*
941+
* The "X-Forwarded-Proto" header must contain the protocol: "https" or "http".
942+
*
943+
* If your reverse proxy uses a different header name than "X-Forwarded-Proto"
944+
* ("SSL_HTTPS" for instance), configure it via "setTrustedHeaderName()" with
945+
* the "client-proto" key.
946+
*
861947
* @return Boolean
862948
*
863949
* @api
864950
*/
865951
public function isSecure()
866952
{
867-
return (
868-
(strtolower($this->server->get('HTTPS')) == 'on' || $this->server->get('HTTPS') == 1)
869-
||
870-
(self::$trustProxy && strtolower($this->headers->get('SSL_HTTPS')) == 'on' || $this->headers->get('SSL_HTTPS') == 1)
871-
||
872-
(self::$trustProxy && strtolower($this->headers->get('X_FORWARDED_PROTO')) == 'https')
873-
);
953+
if (self::$trustProxyData && self::$trustedHeaders[self::HEADER_CLIENT_PROTO] && $proto = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_PROTO])) {
954+
return in_array(strtolower($proto), array('https', 'on', '1'));
955+
}
956+
957+
return 'on' == strtolower($this->server->get('HTTPS')) || 1 == $this->server->get('HTTPS');
874958
}
875959

876960
/**
877961
* Returns the host name.
878962
*
963+
* This method can read the client port from the "X-Forwarded-Host" header
964+
* when trusted proxies were set via "setTrustedProxies()".
965+
*
966+
* The "X-Forwarded-Host" header must contain the client host name.
967+
*
968+
* If your reverse proxy uses a different header name than "X-Forwarded-Host",
969+
* configure it via "setTrustedHeaderName()" with the "client-host" key.
970+
*
879971
* @return string
880972
*
881973
* @api
882974
*/
883975
public function getHost()
884976
{
885-
if (self::$trustProxy && $host = $this->headers->get('X_FORWARDED_HOST')) {
977+
if (self::$trustProxyData && self::$trustedHeaders[self::HEADER_CLIENT_HOST] && $host = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_HOST])) {
886978
$elements = explode(',', $host);
887979

888980
$host = trim($elements[count($elements) - 1]);

0 commit comments

Comments
 (0)
0