@@ -15,6 +15,15 @@ def get_remote_host(request: HttpRequest) -> Optional[str]:
1515 return value [0 ] if value else None
1616
1717
18+ def split_header (value : str ) -> list [str ]:
19+ values = []
20+ for a_value in value .split (',' ):
21+ a_value = a_value .strip ()
22+ if a_value :
23+ values .append (a_value )
24+ return values
25+
26+
1827def get_remote_hosts (request : HttpRequest , get_first_only : bool = False ) -> list [str ]:
1928 '''
2029 Get all IPs from the allowed headers
@@ -27,24 +36,32 @@ def get_remote_hosts(request: HttpRequest, get_first_only: bool = False) -> list
2736
2837 headers = get_setting ('REMOTE_HOST_HEADERS' , ['REMOTE_ADDR' , 'REMOTE_HOST' ])
2938
39+ for header in headers :
40+ for value in split_header (request .META .get (header , '' )):
41+ remote_hosts .append (value )
42+
3043 # If we are connected to from a trusted proxy then we can add some additional headers
3144 try :
3245 if 'HTTP_X_TRUSTED_PROXY' in request .META :
3346 if validate_x_trusted_proxy_header (request .META ['HTTP_X_TRUSTED_PROXY' ]):
34- headers .insert (0 , 'HTTP_X_FORWARDED_FOR' )
35- headers .insert (0 , 'HTTP_X_ENVOY_EXTERNAL_ADDRESS' )
47+ # The last entry in x-forwarded-for from envoy can be trusted implicitly
48+ # https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers#x-forwarded-for
49+ values = split_header (request .META .get ('HTTP_X_FORWARDED_FOR' , '' ))
50+ if values :
51+ remote_hosts .insert (0 , values [- 1 ])
52+
53+ # x-envoy-external-address can always be trusted when coming from envoy
54+ # https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers#x-envoy-external-address
55+ for value in reversed (split_header (request .META .get ('HTTP_X_ENVOY_EXTERNAL_ADDRESS' , '' ))):
56+ remote_hosts .insert (0 , value )
3657 else :
3758 logger .error ("Unable to use headers from trusted proxy because shared secret was invalid!" )
3859 except Exception :
3960 logger .exception ("Failed to validate HTTP_X_TRUSTED_PROXY" )
4061
41- for header in headers :
42- for value in request .META .get (header , '' ).split (',' ):
43- value = value .strip ()
44- if value :
45- if get_first_only :
46- return [value ]
47- remote_hosts .append (value )
62+ if get_first_only and len (remote_hosts ) > 0 :
63+ return [remote_hosts [0 ]]
64+
4865 return remote_hosts
4966
5067
0 commit comments