Commit 6c934509 authored by Dries's avatar Dries

- Patch #621748 by grendzy, David Strauss: ip_address() is broken for multi-tier architectures.

parent b32e3c90
...@@ -2493,13 +2493,21 @@ function ip_address() { ...@@ -2493,13 +2493,21 @@ function ip_address() {
// If an array of known reverse proxy IPs is provided, then trust // If an array of known reverse proxy IPs is provided, then trust
// the XFF header if request really comes from one of them. // the XFF header if request really comes from one of them.
$reverse_proxy_addresses = variable_get('reverse_proxy_addresses', array()); $reverse_proxy_addresses = variable_get('reverse_proxy_addresses', array());
if (!empty($reverse_proxy_addresses) && in_array($ip_address, $reverse_proxy_addresses, TRUE)) {
// The "X-Forwarded-For" header is a comma+space separated list of IP addresses, // Turn XFF header into an array.
// the left-most being the farthest downstream client. If there is more than $forwarded = explode(',', $_SERVER[$reverse_proxy_header]);
// one proxy, we are interested in the most recent one (i.e. last one in the list).
$ip_address_parts = explode(',', $_SERVER[$reverse_proxy_header]); // Trim the forwarded IPs; they may have been delimited by commas and spaces.
$ip_address = trim(array_pop($ip_address_parts)); $forwarded = array_map('trim', $forwarded);
}
// Tack direct client IP onto end of forwarded array.
$forwarded[] = $ip_address;
// 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);
} }
} }
} }
......
...@@ -16,8 +16,9 @@ class BootstrapIPAddressTestCase extends DrupalWebTestCase { ...@@ -16,8 +16,9 @@ class BootstrapIPAddressTestCase extends DrupalWebTestCase {
$this->remote_ip = '127.0.0.1'; $this->remote_ip = '127.0.0.1';
$this->proxy_ip = '127.0.0.2'; $this->proxy_ip = '127.0.0.2';
$this->forwarded_ip = '127.0.0.3'; $this->proxy2_ip = '127.0.0.3';
$this->cluster_ip = '127.0.0.4'; $this->forwarded_ip = '127.0.0.4';
$this->cluster_ip = '127.0.0.5';
$this->untrusted_ip = '0.0.0.0'; $this->untrusted_ip = '0.0.0.0';
drupal_static_reset('ip_address'); drupal_static_reset('ip_address');
...@@ -42,23 +43,23 @@ class BootstrapIPAddressTestCase extends DrupalWebTestCase { ...@@ -42,23 +43,23 @@ class BootstrapIPAddressTestCase extends DrupalWebTestCase {
// Test the normal IP address. // Test the normal IP address.
$this->assertTrue( $this->assertTrue(
ip_address() == $this->remote_ip, ip_address() == $this->remote_ip,
t('Got remote IP address') t('Got remote IP address.')
); );
// Proxy forwarding on but no proxy addresses defined. // Proxy forwarding on but no proxy addresses defined.
variable_set('reverse_proxy', 1); variable_set('reverse_proxy', 1);
$this->assertTrue( $this->assertTrue(
ip_address() == $this->remote_ip, ip_address() == $this->remote_ip,
t('Proxy forwarding without trusted proxies got remote IP address') t('Proxy forwarding without trusted proxies got remote IP address.')
); );
// Proxy forwarding on and proxy address not trusted. // Proxy forwarding on and proxy address not trusted.
variable_set('reverse_proxy_addresses', array($this->proxy_ip)); variable_set('reverse_proxy_addresses', array($this->proxy_ip, $this->proxy2_ip));
drupal_static_reset('ip_address'); drupal_static_reset('ip_address');
$_SERVER['REMOTE_ADDR'] = $this->untrusted_ip; $_SERVER['REMOTE_ADDR'] = $this->untrusted_ip;
$this->assertTrue( $this->assertTrue(
ip_address() == $this->untrusted_ip, ip_address() == $this->untrusted_ip,
t('Proxy forwarding with untrusted proxy got remote IP address') t('Proxy forwarding with untrusted proxy got remote IP address.')
); );
// Proxy forwarding on and proxy address trusted. // Proxy forwarding on and proxy address trusted.
...@@ -67,7 +68,16 @@ class BootstrapIPAddressTestCase extends DrupalWebTestCase { ...@@ -67,7 +68,16 @@ class BootstrapIPAddressTestCase extends DrupalWebTestCase {
drupal_static_reset('ip_address'); drupal_static_reset('ip_address');
$this->assertTrue( $this->assertTrue(
ip_address() == $this->forwarded_ip, ip_address() == $this->forwarded_ip,
t('Proxy forwarding with trusted proxy got forwarded IP address') t('Proxy forwarding with trusted proxy got forwarded IP address.')
);
// Multi-tier architecture with comma separated values in header.
$_SERVER['REMOTE_ADDR'] = $this->proxy_ip;
$_SERVER['HTTP_X_FORWARDED_FOR'] = implode(', ', array($this->untrusted_ip, $this->forwarded_ip, $this->proxy2_ip));
drupal_static_reset('ip_address');
$this->assertTrue(
ip_address() == $this->forwarded_ip,
t('Proxy forwarding with trusted 2-tier proxy got forwarded IP address.')
); );
// Custom client-IP header. // Custom client-IP header.
...@@ -76,8 +86,10 @@ class BootstrapIPAddressTestCase extends DrupalWebTestCase { ...@@ -76,8 +86,10 @@ class BootstrapIPAddressTestCase extends DrupalWebTestCase {
drupal_static_reset('ip_address'); drupal_static_reset('ip_address');
$this->assertTrue( $this->assertTrue(
ip_address() == $this->cluster_ip, ip_address() == $this->cluster_ip,
t('Cluster environment got cluster client IP') t('Cluster environment got cluster client IP.')
); );
// Verifies that drupal_valid_http_host() prevents invalid characters.
$this->assertFalse(drupal_valid_http_host('security/.drupal.org:80'), t('HTTP_HOST with / is invalid')); $this->assertFalse(drupal_valid_http_host('security/.drupal.org:80'), t('HTTP_HOST with / is invalid'));
$this->assertFalse(drupal_valid_http_host('security\\.drupal.org:80'), t('HTTP_HOST with \\ is invalid')); $this->assertFalse(drupal_valid_http_host('security\\.drupal.org:80'), t('HTTP_HOST with \\ is invalid'));
$this->assertFalse(drupal_valid_http_host('security<.drupal.org:80'), t('HTTP_HOST with &lt; is invalid')); $this->assertFalse(drupal_valid_http_host('security<.drupal.org:80'), t('HTTP_HOST with &lt; is invalid'));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment