Add config variable 'proxy_whitelist'

HTTP headers X_FORWARDED_* and X_REAL_IP are only evaluated when
received from an IP listed in proxy_whitelist. Furthermore, only the
last non-trusted IP from X-Forwarded-For is used in place of the real
ip.

Without this, an attacker can easily spoof the headers and control the
result of the ip or ssl check.

This fixes several problems with [3a4c9f42], [4d480b36] and [a520f331] as
mentioned in #1489729.
pull/173/head
Felix Eckhofer 11 years ago
parent 3fca238554
commit ef721fc430

@ -1,6 +1,7 @@
CHANGELOG Roundcube Webmail CHANGELOG Roundcube Webmail
=========================== ===========================
- Add proxy_whitelist configuration option (#1489729)
- Added toolbar button to move message in message view - Added toolbar button to move message in message view
- Improve UI integration of ACL settings - Improve UI integration of ACL settings
- Drop support for PHP < 5.3.7 - Drop support for PHP < 5.3.7

@ -358,6 +358,10 @@ $config['memcache_hosts'] = null; // e.g. array( 'localhost:11211', '192.168.1.1
// check client IP in session authorization // check client IP in session authorization
$config['ip_check'] = false; $config['ip_check'] = false;
// List of trusted proxies
// X_FORWARDED_* and X_REAL_IP headers are only accepted from these IPs
$config['proxy_whitelist'] = array();
// check referer of incoming requests // check referer of incoming requests
$config['referer_check'] = false; $config['referer_check'] = false;

@ -598,7 +598,9 @@ class rcube_utils
if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off') { if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off') {
return true; return true;
} }
if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https') { if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])
&& strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https'
&& in_array($_SERVER['REMOTE_ADDR'], rcube::get_instance()->config->get('proxy_whitelist', array()))) {
return true; return true;
} }
if ($port && $_SERVER['SERVER_PORT'] == $port) { if ($port && $_SERVER['SERVER_PORT'] == $port) {
@ -683,14 +685,23 @@ class rcube_utils
*/ */
public static function remote_addr() public static function remote_addr()
{ {
// Check if any of the headers are set first to improve performance
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) || !empty($_SERVER['HTTP_X_REAL_IP'])) {
$proxy_whitelist = rcube::get_instance()->config->get('proxy_whitelist', array());
if (in_array($_SERVER['REMOTE_ADDR'], $proxy_whitelist)) {
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$hosts = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'], 2); foreach(array_reverse(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])) as $forwarded_ip) {
return $hosts[0]; if (!in_array($forwarded_ip, $proxy_whitelist)) {
return $forwarded_ip;
}
}
} }
if (!empty($_SERVER['HTTP_X_REAL_IP'])) { if (!empty($_SERVER['HTTP_X_REAL_IP'])) {
return $_SERVER['HTTP_X_REAL_IP']; return $_SERVER['HTTP_X_REAL_IP'];
} }
}
}
if (!empty($_SERVER['REMOTE_ADDR'])) { if (!empty($_SERVER['REMOTE_ADDR'])) {
return $_SERVER['REMOTE_ADDR']; return $_SERVER['REMOTE_ADDR'];

Loading…
Cancel
Save