The current ip_address() function returns an IP address with a space if there are multiple IPs listed in the XFF header with comma+space separation. Also, the function is unable to handle anything but a simple, single reverse proxy layer. Common enterprise architectures use CDNs, load-balancers, and reverse proxies, often in that order.

This change does not break compatibility with existing configurations.

A patch (attached here) has been committed to Pressflow 6:
https://code.launchpad.net/~pressflow/pressflow/multilayer-proxy-support...

Comments

david strauss’s picture

Assigned: Unassigned » david strauss

Assigning to me.

damien tournoud’s picture

Status: Active » Needs work
+++ includes/bootstrap.inc	2009-10-29 16:08:09 +0000
@@ -1439,15 +1439,28 @@
+      // Turn XFF header into an array.
+      $forwarded = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
+      
+      // Tack direct client IP onto end of forwarded array.
+      $forwarded[] = $ip_address;
+      
+      // Trim the forwarded IPs; they may have been delimited by commas and spaces.
+      $forwarded = array_map('trim', $forwarded);

I would do the array_map() on the same line as the explode. Is there a need to trim the IP address from REMOTE_ADDR?

+++ includes/bootstrap.inc	2009-10-29 16:08:09 +0000
@@ -1439,15 +1439,28 @@
+      // Eliminate all trusted IPs.
+      $untrusted = array_diff($forwarded, $reverse_proxy_addresses);
+      
+      // The right-most IP is the most specific we can trust.
+      $ip_address = array_pop($untrusted);

This do not perform as strictly as intended:

+    // Only use parts of the X-Forwarded-For (XFF) header that have followed a trusted route.
+    // Specifically, identify the leftmost IP address in the XFF header that is not one of ours.
+    // An XFF header is: X-Forwarded-For: client1, proxy1, proxy2

We need something like:

do {
  $candidate = array_pop($forwarded);
}
while (in_array($candidate, $reverse_proxy_addresses));

$ip_address = $candidate;

This review is powered by Dreditor.

david strauss’s picture

Is there a need to trim the IP address from REMOTE_ADDR?

Yes. IPs listed in XFF are delimited by commas which may or may not be followed by spaces.

This do not perform as strictly as intended:

Untrue. It's unnecessary to loop as you've suggested. It's not possible for incoming requests to forge entires to the right of ones added by your own proxies. The only side-effect to the array_diff() is that we extract potentially forged items to the left of the user's actual IP, but that won't affect the result.

Show at least one case where it makes a difference.

david strauss’s picture

Status: Needs work » Needs review

Setting back to "needs review," despite the tiny critique about combining the trim and explode onto one line.

david strauss’s picture

Oh, REMOTE_ADDR. I had read "XFF." No, there's no need to trim that. I agree that we should tack it on following the trim.

Status: Needs review » Needs work

The last submitted patch failed testing.

catch’s picture

Status: Needs work » Closed (duplicate)

This is a duplicate of #621748: ip_address() is broken for multi-tier architectures - which has tests. Marking duplicate so they can be combined.

david strauss’s picture

Status: Closed (duplicate) » Needs work

@catch You just marked this a duplicate of itself.

catch’s picture

sun.core’s picture

Status: Needs work » Needs review

7X29YcLCtUMmeqrdQz67VW3RXwU.patch queued for re-testing.

Status: Needs review » Needs work

The last submitted patch, 7X29YcLCtUMmeqrdQz67VW3RXwU.patch, failed testing.

catch’s picture

Status: Needs work » Closed (duplicate)

Back to duplicate.

catch’s picture

Status: Closed (duplicate) » Needs work

The other issue was never combined with this one and didn't fix the specific issue, but has since been committed, so re-opening this, sorry :(

grendzy’s picture

Assigned: david strauss » grendzy
Status: Needs work » Needs review
StatusFileSize
new4.78 KB

David's fix, with additional test for the multi-tier environment. REMOTE_ADDR is no longer trimmed. Also includes some minor style / doc fixes.

dries’s picture

Version: 7.x-dev » 6.x-dev

Committed to CVS HEAD for inclusion in Drupal 7. This should probably be backported to Drupal 6.

mikeytown2’s picture

StatusFileSize
new2.18 KB
grendzy’s picture

Status: Needs review » Needs work

I think it's good that the reverse_proxy_header variable is included in the backport, but there's some additional documentation that goes with it in default.settings.php

mikeytown2’s picture

Status: Needs work » Needs review
StatusFileSize
new3.05 KB
new3.05 KB

added in the documentation to default.settings.php

janusman’s picture

StatusFileSize
new3.05 KB

I think the testing bot is ignoring the patch due to the -D6 in the name. Attaching same patch from #18, renamed.

mikeytown2’s picture

@janusman
This patch is for 6.x it was already applied for 7.x

Have you tested this on 6.x yet?

Status: Needs review » Needs work

The last submitted patch, drupal-621748-19.patch, failed testing.

grendzy’s picture

Status: Needs work » Needs review

bad bot! This is a D6 patch.

vacilando’s picture

This is a problem for Pantheon as well. Subscribing.

_-.’s picture

Did this patch make it into Drupal7 _release_? Or, n/a 'til next point release ... ?

mikeytown2’s picture

I use this patch; anyone else want to test and give it the thumbs up so we can RTBC this?

This is in D7

canishk’s picture

#14: 621748_multi_tier.patch queued for re-testing.

verta’s picture

Status: Needs work » Needs review

#19: drupal-621748-19.patch queued for re-testing.
(edit: just trying to figure out how to get this patch tested.)

Status: Needs review » Needs work

The last submitted patch, drupal-621748-19.patch, failed testing.

mikeytown2’s picture

Status: Needs review » Needs work

@verta
That patch needs to be re-rolled from git.

verta’s picture

OK, thanks.

dmitriy.trt’s picture

What about situation when we don't know exact IP address of trusted proxy? But we're sure that proxy exists. For example, we have a load balancer with dynamic internal IP address. So, we can't just add its IP to the list of reverse_proxy_addresses in settings.php, because it would work until the next IP address change.

My suggestion is to support "*" in reverse_proxy_addresses variable in addition to fixed IP addresses.

grendzy’s picture

dmitriy.trt’s picture

Setting $_SERVER['REMOTE_ADDR'] directly in settings.php is not perfect solution, but it is acceptable. Thanks.

bradjones1’s picture

Priority: Critical » Normal

No action for over a year indicates this isn't critical; also if this is still present in 7.x or 8.x, should be marked 8.x and backported as appropriate.

mikeytown2’s picture

This is fixed in 7.x (#15) and thus 8.x as well.
Main reason this isn't getting a lot of attention is most people who have this issue switch to pressflow. I'll see if I get some time today and do a re-roll of this.

robloach’s picture

Status: Needs work » Needs review
StatusFileSize
new2.65 KB

Updated the patch. Would appreciate some testing.

jkealy’s picture

Rob,

I'm going to test the patch this week. I'll let you know how it goes.

Best regards,

John Kealy

jkealy’s picture

Rob,

Patch passed test on staging and was moved to production. The patch has solved the infinite redirect problem we were getting earlier on IP based logins. Thanks!

Cheers,

JK

agileware’s picture

Issue summary: View changes
Status: Needs review » Reviewed & tested by the community

Can confirm patch #36 works in production.

Status: Reviewed & tested by the community » Closed (outdated)

Automatically closed because Drupal 6 is no longer supported. If the issue verifiably applies to later versions, please reopen with details and update the version.