From f58a294949547ed132bf3cdb5815b68c659b992a Mon Sep 17 00:00:00 2001 From: Felix Eckhofer Date: Wed, 26 Mar 2014 14:13:40 +0100 Subject: 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. Conflicts: CHANGELOG --- program/lib/Roundcube/rcube_utils.php | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'program/lib/Roundcube') diff --git a/program/lib/Roundcube/rcube_utils.php b/program/lib/Roundcube/rcube_utils.php index ae3e3a414..c2009cee0 100644 --- a/program/lib/Roundcube/rcube_utils.php +++ b/program/lib/Roundcube/rcube_utils.php @@ -596,7 +596,9 @@ class rcube_utils if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off') { 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; } if ($port && $_SERVER['SERVER_PORT'] == $port) { @@ -681,13 +683,22 @@ class rcube_utils */ public static function remote_addr() { - if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { - $hosts = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'], 2); - return $hosts[0]; - } + // 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'])) { + foreach(array_reverse(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])) as $forwarded_ip) { + if (!in_array($forwarded_ip, $proxy_whitelist)) { + return $forwarded_ip; + } + } + } - if (!empty($_SERVER['HTTP_X_REAL_IP'])) { - return $_SERVER['HTTP_X_REAL_IP']; + if (!empty($_SERVER['HTTP_X_REAL_IP'])) { + return $_SERVER['HTTP_X_REAL_IP']; + } + } } if (!empty($_SERVER['REMOTE_ADDR'])) { -- cgit v1.2.3