Skip to content

Commit

Permalink
Enhance TrustProxy to handle multiple chained proxies
Browse files Browse the repository at this point in the history
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
jonjensen committed Apr 2, 2011
1 parent c1d6b1f commit 29c73e6
Showing 1 changed file with 29 additions and 18 deletions.
47 changes: 29 additions & 18 deletions lib/Vend/Server.pm
Expand Up @@ -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;
}
}
}
Expand Down

0 comments on commit 29c73e6

Please sign in to comment.