@@ -206,6 +206,15 @@ class Request
206
206
207
207
protected static $ requestFactory ;
208
208
209
+ private $ isForwardedValid = true ;
210
+
211
+ private static $ forwardedParams = array (
212
+ self ::HEADER_CLIENT_IP => 'for ' ,
213
+ self ::HEADER_CLIENT_HOST => 'host ' ,
214
+ self ::HEADER_CLIENT_PROTO => 'proto ' ,
215
+ self ::HEADER_CLIENT_PORT => 'host ' ,
216
+ );
217
+
209
218
/**
210
219
* Constructor.
211
220
*
@@ -806,41 +815,13 @@ public function setSession(SessionInterface $session)
806
815
*/
807
816
public function getClientIps ()
808
817
{
809
- $ clientIps = array ();
810
818
$ ip = $ this ->server ->get ('REMOTE_ADDR ' );
811
819
812
820
if (!$ this ->isFromTrustedProxy ()) {
813
821
return array ($ ip );
814
822
}
815
823
816
- $ hasTrustedForwardedHeader = self ::$ trustedHeaders [self ::HEADER_FORWARDED ] && $ this ->headers ->has (self ::$ trustedHeaders [self ::HEADER_FORWARDED ]);
817
- $ hasTrustedClientIpHeader = self ::$ trustedHeaders [self ::HEADER_CLIENT_IP ] && $ this ->headers ->has (self ::$ trustedHeaders [self ::HEADER_CLIENT_IP ]);
818
-
819
- if ($ hasTrustedForwardedHeader ) {
820
- $ forwardedHeader = $ this ->headers ->get (self ::$ trustedHeaders [self ::HEADER_FORWARDED ]);
821
- preg_match_all ('{(for)=("?\[?)([a-z0-9\.:_\-/]*)} ' , $ forwardedHeader , $ matches );
822
- $ forwardedClientIps = $ matches [3 ];
823
-
824
- $ forwardedClientIps = $ this ->normalizeAndFilterClientIps ($ forwardedClientIps , $ ip );
825
- $ clientIps = $ forwardedClientIps ;
826
- }
827
-
828
- if ($ hasTrustedClientIpHeader ) {
829
- $ xForwardedForClientIps = array_map ('trim ' , explode (', ' , $ this ->headers ->get (self ::$ trustedHeaders [self ::HEADER_CLIENT_IP ])));
830
-
831
- $ xForwardedForClientIps = $ this ->normalizeAndFilterClientIps ($ xForwardedForClientIps , $ ip );
832
- $ clientIps = $ xForwardedForClientIps ;
833
- }
834
-
835
- if ($ hasTrustedForwardedHeader && $ hasTrustedClientIpHeader && $ forwardedClientIps !== $ xForwardedForClientIps ) {
836
- 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 Symfony to distrust one of them. ' );
837
- }
838
-
839
- if (!$ hasTrustedForwardedHeader && !$ hasTrustedClientIpHeader ) {
840
- return $ this ->normalizeAndFilterClientIps (array (), $ ip );
841
- }
842
-
843
- return $ clientIps ;
824
+ return $ this ->getTrustedValues (self ::HEADER_CLIENT_IP , $ ip ) ?: array ($ ip );
844
825
}
845
826
846
827
/**
@@ -966,31 +947,25 @@ public function getScheme()
966
947
*/
967
948
public function getPort ()
968
949
{
969
- if ($ this ->isFromTrustedProxy ()) {
970
- if (self ::$ trustedHeaders [self ::HEADER_CLIENT_PORT ] && $ port = $ this ->headers ->get (self ::$ trustedHeaders [self ::HEADER_CLIENT_PORT ])) {
971
- return (int ) $ port ;
972
- }
973
-
974
- if (self ::$ trustedHeaders [self ::HEADER_CLIENT_PROTO ] && 'https ' === $ this ->headers ->get (self ::$ trustedHeaders [self ::HEADER_CLIENT_PROTO ], 'http ' )) {
975
- return 443 ;
976
- }
950
+ if ($ this ->isFromTrustedProxy () && $ host = $ this ->getTrustedValues (self ::HEADER_CLIENT_PORT )) {
951
+ $ host = $ host [0 ];
952
+ } elseif ($ this ->isFromTrustedProxy () && $ host = $ this ->getTrustedValues (self ::HEADER_CLIENT_HOST )) {
953
+ $ host = $ host [0 ];
954
+ } elseif (!$ host = $ this ->headers ->get ('HOST ' )) {
955
+ return $ this ->server ->get ('SERVER_PORT ' );
977
956
}
978
957
979
- if ($ host = $ this ->headers ->get ('HOST ' )) {
980
- if ($ host [0 ] === '[ ' ) {
981
- $ pos = strpos ($ host , ': ' , strrpos ($ host , '] ' ));
982
- } else {
983
- $ pos = strrpos ($ host , ': ' );
984
- }
985
-
986
- if (false !== $ pos ) {
987
- return (int ) substr ($ host , $ pos + 1 );
988
- }
958
+ if ($ host [0 ] === '[ ' ) {
959
+ $ pos = strpos ($ host , ': ' , strrpos ($ host , '] ' ));
960
+ } else {
961
+ $ pos = strrpos ($ host , ': ' );
962
+ }
989
963
990
- return 'https ' === $ this ->getScheme () ? 443 : 80 ;
964
+ if (false !== $ pos ) {
965
+ return (int ) substr ($ host , $ pos + 1 );
991
966
}
992
967
993
- return $ this ->server -> get ( ' SERVER_PORT ' ) ;
968
+ return ' https ' === $ this ->getScheme () ? 443 : 80 ;
994
969
}
995
970
996
971
/**
@@ -1190,8 +1165,8 @@ public function getQueryString()
1190
1165
*/
1191
1166
public function isSecure ()
1192
1167
{
1193
- if ($ this ->isFromTrustedProxy () && self :: $ trustedHeaders [ self :: HEADER_CLIENT_PROTO ] && $ proto = $ this ->headers -> get (self ::$ trustedHeaders [ self :: HEADER_CLIENT_PROTO ] )) {
1194
- return in_array (strtolower (current ( explode ( ' , ' , $ proto))) , array ('https ' , 'on ' , 'ssl ' , '1 ' ));
1168
+ if ($ this ->isFromTrustedProxy () && $ proto = $ this ->getTrustedValues (self ::HEADER_CLIENT_PROTO )) {
1169
+ return in_array (strtolower ($ proto[ 0 ]) , array ('https ' , 'on ' , 'ssl ' , '1 ' ), true );
1195
1170
}
1196
1171
1197
1172
$ https = $ this ->server ->get ('HTTPS ' );
@@ -1216,10 +1191,8 @@ public function isSecure()
1216
1191
*/
1217
1192
public function getHost ()
1218
1193
{
1219
- if ($ this ->isFromTrustedProxy () && self ::$ trustedHeaders [self ::HEADER_CLIENT_HOST ] && $ host = $ this ->headers ->get (self ::$ trustedHeaders [self ::HEADER_CLIENT_HOST ])) {
1220
- $ elements = explode (', ' , $ host , 2 );
1221
-
1222
- $ host = $ elements [0 ];
1194
+ if ($ this ->isFromTrustedProxy () && $ host = $ this ->getTrustedValues (self ::HEADER_CLIENT_HOST )) {
1195
+ $ host = $ host [0 ];
1223
1196
} elseif (!$ host = $ this ->headers ->get ('HOST ' )) {
1224
1197
if (!$ host = $ this ->server ->get ('SERVER_NAME ' )) {
1225
1198
$ host = $ this ->server ->get ('SERVER_ADDR ' , '' );
@@ -1948,8 +1921,48 @@ private function isFromTrustedProxy()
1948
1921
return self ::$ trustedProxies && IpUtils::checkIp ($ this ->server ->get ('REMOTE_ADDR ' ), self ::$ trustedProxies );
1949
1922
}
1950
1923
1924
+ private function getTrustedValues ($ type , $ ip = null )
1925
+ {
1926
+ $ clientValues = array ();
1927
+ $ forwardedValues = array ();
1928
+
1929
+ if (self ::$ trustedHeaders [$ type ] && $ this ->headers ->has (self ::$ trustedHeaders [$ type ])) {
1930
+ foreach (explode (', ' , $ this ->headers ->get (self ::$ trustedHeaders [$ type ])) as $ v ) {
1931
+ $ clientValues [] = (self ::HEADER_CLIENT_PORT === $ type ? '0.0.0.0: ' : '' ).trim ($ v );
1932
+ }
1933
+ }
1934
+
1935
+ if (self ::$ trustedHeaders [self ::HEADER_FORWARDED ] && $ this ->headers ->has (self ::$ trustedHeaders [self ::HEADER_FORWARDED ])) {
1936
+ $ forwardedValues = $ this ->headers ->get (self ::$ trustedHeaders [self ::HEADER_FORWARDED ]);
1937
+ $ forwardedValues = preg_match_all (sprintf ('{(?:%s)=(?:"?\[?)([a-zA-Z0-9\.:_\-/]*+)} ' , self ::$ forwardedParams [$ type ]), $ forwardedValues , $ matches ) ? $ matches [1 ] : array ();
1938
+ }
1939
+
1940
+ if (null !== $ ip ) {
1941
+ $ clientValues = $ this ->normalizeAndFilterClientIps ($ clientValues , $ ip );
1942
+ $ forwardedValues = $ this ->normalizeAndFilterClientIps ($ forwardedValues , $ ip );
1943
+ }
1944
+
1945
+ if ($ forwardedValues === $ clientValues || !$ clientValues ) {
1946
+ return $ forwardedValues ;
1947
+ }
1948
+
1949
+ if (!$ forwardedValues ) {
1950
+ return $ clientValues ;
1951
+ }
1952
+
1953
+ if (!$ this ->isForwardedValid ) {
1954
+ return null !== $ ip ? array ('0.0.0.0 ' , $ ip ) : array ();
1955
+ }
1956
+ $ this ->isForwardedValid = false ;
1957
+
1958
+ 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 one of them, or configure your project to distrust the offending one. ' , self ::$ trustedHeaders [self ::HEADER_FORWARDED ], self ::$ trustedHeaders [$ type ]));
1959
+ }
1960
+
1951
1961
private function normalizeAndFilterClientIps (array $ clientIps , $ ip )
1952
1962
{
1963
+ if (!$ clientIps ) {
1964
+ return array ();
1965
+ }
1953
1966
$ clientIps [] = $ ip ; // Complete the IP chain with the IP the request actually came from
1954
1967
$ firstTrustedIp = null ;
1955
1968
0 commit comments