[interchange] Enhance TrustProxy to handle multiple chained proxies

Jon Jensen interchange-cvs at icdevgroup.org
Sat Apr 2 19:18:38 UTC 2011


commit 29c73e67feb9240bca3a60288cad7d7293f482c9
Author: Jon Jensen <jon at endpoint.com>
Date:   Thu Mar 31 22:24:07 2011 -0500

    Enhance TrustProxy to handle multiple chained proxies
    
    This can happen if, for example, you have a first proxy at 10.10.10.1
    which proxies to 10.10.10.2 which then hits your web server that passes
    control to Interchange.
    
    If you visit from 192.168.1.1, Interchange will see this HTTP header:
    
    X-Forwarded-For: 192.168.1.1, 10.10.10.1
    
    and the request will have the source IP address 10.10.10.2.
    
    But if you set this in interchange.cfg:
    
    TrustProxy 10.10.10.1, 10.10.10.2    # order irrelevant
    
    then Interchange will see past the two trusted proxies and set its
    standard variable $CGI::remote_addr to 192.168.1.1, so that the customer's
    IP address gets used.

 lib/Vend/Server.pm |   47 +++++++++++++++++++++++++++++------------------
 1 files changed, 29 insertions(+), 18 deletions(-)
---
diff --git a/lib/Vend/Server.pm b/lib/Vend/Server.pm
index 7305cec..a6620f5 100644
--- a/lib/Vend/Server.pm
+++ b/lib/Vend/Server.pm
@@ -127,26 +127,37 @@ sub populate {
 
 	# try to get originating host's IP address if request was
 	# forwarded through a trusted proxy
-	my $ip;
-	if ($Global::TrustProxy
-		and ($CGI::remote_addr =~ $Global::TrustProxy
-			or $CGI::remote_host =~ $Global::TrustProxy)
-		and $ip = $cgivar->{HTTP_X_FORWARDED_FOR}) {
-		# trust only the last hop's IP address before our trusted proxy
-		# when multiples are present in a comma-separated list
-		$ip =~ s/.*,//;
-		$ip =~ s/^\s+//; $ip =~ s/\s+$//;
-		if ($ip =~ /^\d\d?\d?\.\d\d?\d?\.\d\d?\d?\.\d\d?\d?$/) {
+	if (
+		$Global::TrustProxy
+		and (
+			$CGI::remote_addr =~ $Global::TrustProxy
+			or $CGI::remote_host =~ $Global::TrustProxy
+		)
+		and my $forwarded_for = $cgivar->{HTTP_X_FORWARDED_FOR}
+	) {
+		# multiple source IP addresses may appear in X-Forwarded-For header
+		# in a comma-separated list
+		for my $ip (reverse grep /\S/, split /\s*,\s*/, $forwarded_for) {
+			# do we have a valid-looking IP address?
+			if ($ip !~ /^\d\d?\d?\.\d\d?\d?\.\d\d?\d?\.\d\d?\d?$/) {
+				# if not, log error and ignore X-Forwarded-For header
+				::logGlobal(
+					{ level => 'info' },
+					"Unknown X-Forwarded-For header set from trusted proxy %s: %s",
+					$CGI::remote_addr,
+					$forwarded_for,
+				);
+				last;
+			}
+
+			# skip any other upstream trusted proxies
+			next if $ip =~ $Global::TrustProxy;
+
+			# rightmost IP address that's not a trusted proxy is the customer IP
+			# address as far as we're concerned, so keep that and exit loop
 			$CGI::remote_addr = $ip;
 			undef $CGI::remote_host;
-		}
-		else {
-			::logGlobal(
-				{ level => 'info' },
-				"Unknown HTTP_X_FORWARDED_FOR header set from trusted proxy %s: '%s'",
-				$CGI::remote_addr,
-				$cgivar->{HTTP_X_FORWARDED_FOR},
-			);
+			last;
 		}
 	}
 }



More information about the interchange-cvs mailing list