8000 Merge branch '2.1' · symfony/symfony@995219f · GitHub
[go: up one dir, main page]

Skip to content

Commit 995219f

Browse files
committed
Merge branch '2.1'
* 2.1: 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/Tests/RequestTest.php
2 parents 18495e7 + 6c67476 commit 995219f

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
protected static $httpMethodParameterOverride = false;
3657

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

454511
/**
@@ -597,31 +654,43 @@ public function setSession(SessionInterface $session)
597654
/**
598655
* Returns the client IP address.
599656
*
657+
* This method can read the client IP address from the "X-Forwarded-For" header
658+
* when trusted proxies were set via "setTrustedProxies()". The "X-Forwarded-For"
659+
* header value is a comma+space separated list of IP addresses, the left-most
660+
* being the original client, and each successive proxy that passed the request
661+
* adding the IP address where it received the request from.
662+
*
663+
* If your reverse proxy uses a different header name than "X-Forwarded-For",
664+
* ("Client-Ip" for instance), configure it via "setTrustedHeaderName()" with
665+
* the "client-ip" key.
666+
*
600667
* @return string The client IP address
601668
*
669+
* @see http://en.wikipedia.org/wiki/X-Forwarded-For
670+
*
671+
* @deprecated The proxy argument is deprecated since version 2.0 and will be removed in 2.3. Use setTrustedProxies instead.
672+
*
602673
* @api
603674
*/
604675
public function getClientIp()
605676
{
606-
if (self::$trustProxy) {
607-
if ($this->server->has('HTTP_CLIENT_IP')) {
608-
return $this->server->get('HTTP_CLIENT_IP');
609-
} elseif ($this->server->has('HTTP_X_FORWARDED_FOR')) {
610-
$clientIp = explode(',', $this->server->get('HTTP_X_FORWARDED_FOR'));
611-
612-
foreach ($clientIp as $ipAddress) {
613-
$cleanIpAddress = trim($ipAddress);
677+
$ip = $this->server->get('REMOTE_ADDR');
614678

615-
if (false !== filter_var($cleanIpAddress, FILTER_VALIDATE_IP)) {
616-
return $cleanIpAddress;
617-
}
618-
}
679+
if (!self::$trustProxyData) {
680+
return $ip;
681+
}
619682

620-
return '';
621-
}
683+
if (!self::$trustedHeaders[self::HEADER_CLIENT_IP] || !$this->headers->has(self::$trustedHeaders[self::HEADER_CLIENT_IP])) {
684+
return $ip;
622685
}
623686

624-
return $this->server->get('REMOTE_ADDR');
687+
$clientIps = array_map('trim', explode(',', $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_IP])));
688+
$clientIps[] = $ip;
689+
690+
$trustedProxies = self::$trustProxyData && !self::$trustedProxies ? array($ip) : self::$trustedProxies;
691+
$clientIps = array_diff($clientIps, $trustedProxies);
692+
693+
return array_pop($clientIps);
625694
}
626695

627696
/**
@@ -720,14 +789,22 @@ public function getScheme()
720789
/**
721790
* Returns the port on which the request is made.
722791
*
792+
* This method can read the client port from the "X-Forwarded-Port" header
793+
* when trusted proxies were set via "setTrustedProxies()".
794+
*
795+
* The "X-Forwarded-Port" header must contain the client port.
796+
*
797+
* If your reverse proxy uses a different header name than "X-Forwarded-Port",
798+
* configure it via "setTrustedHeaderName()" with the "client-port" key.
799+
*
723800
* @return string
724801
*
725802
* @api
726803
*/
727804
public function getPort()
728805
{
729-
if (self::$trustProxy && $this->headers->has('X-Forwarded-Port')) {
730-
return $this->headers->get('X-Forwarded-Port');
806+
if (self::$trustProxyData && self::$trustedHeaders[self::HEADER_CLIENT_PORT] && $port = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_PORT])) {
807+
return $port;
731808
}
732809

733810
return $this->server->get('SERVER_PORT');
@@ -873,31 +950,46 @@ public function getQueryString()
873950
/**
874951
* Checks whether the request is secure or not.
875952
*
953+
* This method can read the client port from the "X-Forwarded-Proto" header
954+
* when trusted proxies were set via "setTrustedProxies()".
955+
*
956+
* The "X-Forwarded-Proto" header must contain the protocol: "https" or "http".
957+
*
958+
* If your reverse proxy uses a different header name than "X-Forwarded-Proto"
959+
* ("SSL_HTTPS" for instance), configure it via "setTrustedHeaderName()" with
960+
* the "client-proto" key.
961+
*
876962
* @return Boolean
877963
*
878964
* @api
879965
*/
880966
public function isSecure()
881967
{
882-
return (
883-
(strtolower($this->server->get('HTTPS')) == 'on' || $this->server->get('HTTPS') == 1)
884-
||
885-
(self::$trustProxy && strtolower($this->headers->get('SSL_HTTPS')) == 'on' || $this->headers->get('SSL_HTTPS') == 1)
886-
||
887-
(self::$trustProxy && strtolower($this->headers->get('X_FORWARDED_PROTO')) == 'https')
888-
);
968+
if (self::$trustProxyData && self::$trustedHeaders[self::HEADER_CLIENT_PROTO] && $proto = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_PROTO])) {
969+
return in_array(strtolower($proto), array('https', 'on', '1'));
970+
}
971+
972+
return 'on' == strtolower($this->server->get('HTTPS')) || 1 == $this->server->get('HTTPS');
889973
}
890974

891975
/**
892976
* Returns the host name.
893977
*
978+
* This method can read the client port from the "X-Forwarded-Host" header
979+
* when trusted proxies were set via "setTrustedProxies()".
980+
*
981+
* The "X-Forwarded-Host" header must contain the client host name.
982+
*
983+
* If your reverse proxy uses a different header name than "X-Forwarded-Host",
984+
* configure it via "setTrustedHeaderName()" with the "client-host" key.
985+
*
894986
* @return string
895987
*
896988
* @api
897989
*/
898990
public function getHost()
899991
{
900-
if (self::$trustProxy && $host = $this->headers->get('X_FORWARDED_HOST')) {
992+
if (self::$trustProxyData && self::$trustedHeaders[self::HEADER_CLIENT_HOST] && $host = $this->headers->get(self::$trustedHeaders[self::HEADER_CLIENT_HOST])) {
901993
$elements = explode(',', $host);
902994

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

0 commit comments

Comments
 (0)
0