Permalink
Browse files

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.
  • Loading branch information...
1 parent c1d6b1f commit 29c73e67feb9240bca3a60288cad7d7293f482c9 @jonjensen jonjensen committed Apr 1, 2011
Showing with 29 additions and 18 deletions.
  1. +29 −18 lib/Vend/Server.pm
View
@@ -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;
}
}
}

0 comments on commit 29c73e6

Please sign in to comment.