Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for getting the real client IP behind proxies #10653

Merged
merged 1 commit into from Aug 27, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions config/config.sample.php
Expand Up @@ -62,6 +62,12 @@
/* List of trusted domains, to prevent host header poisoning ownCloud is only using these Host headers */
'trusted_domains' => array('demo.owncloud.org', 'otherdomain.owncloud.org:8080'),

/* List of trusted proxy servers */
'trusted_proxies' => array('203.0.113.45', '198.51.100.128'),

/* Headers that should be trusted as client IP address in combination with `trusted_proxies` */
'forwarded_for_headers' => array('HTTP_X_FORWARDED', 'HTTP_FORWARDED_FOR'),

/* Theme to use for ownCloud */
"theme" => "",

Expand Down
2 changes: 1 addition & 1 deletion lib/private/allconfig.php
Expand Up @@ -28,7 +28,7 @@ public function setSystemValue($key, $value) {
*
* @param string $key the key of the value, under which it was saved
* @param mixed $default the default value to be returned if the value isn't set
* @return string the saved value
* @return mixed the value or $default
*/
public function getSystemValue($key, $default = '') {
return \OCP\Config::getSystemValue($key, $default);
Expand Down
28 changes: 28 additions & 0 deletions lib/private/request.php
Expand Up @@ -15,6 +15,34 @@ class OC_Request {

const REGEX_LOCALHOST = '/^(127\.0\.0\.1|localhost)(:[0-9]+|)$/';

/**
* Returns the remote address, if the connection came from a trusted proxy and `forwarded_for_headers` has been configured
* then the IP address specified in this header will be returned instead.
* Do always use this instead of $_SERVER['REMOTE_ADDR']
* @return string IP address
*/
public static function getRemoteAddress() {
$remoteAddress = $_SERVER['REMOTE_ADDR'];
$trustedProxies = \OC::$server->getConfig()->getSystemValue('trusted_proxies', array());

if(is_array($trustedProxies) && in_array($remoteAddress, $trustedProxies)) {
$forwardedForHeaders = \OC::$server->getConfig()->getSystemValue('forwarded_for_headers', array());

foreach($forwardedForHeaders as $header) {
if (array_key_exists($header, $_SERVER) === true) {
foreach (explode(',', $_SERVER[$header]) as $IP) {
$IP = trim($IP);
if (filter_var($IP, FILTER_VALIDATE_IP) !== false) {
return $IP;
}
}
}
}
}

return $remoteAddress;
}

/**
* Check overwrite condition
* @param string $type
Expand Down
2 changes: 1 addition & 1 deletion lib/public/config.php
Expand Up @@ -43,7 +43,7 @@ class Config {
* Gets a value from config.php
* @param string $key key
* @param mixed $default = null default value
* @return string the value or $default
* @return mixed the value or $default
*
* This function gets the value from config.php. If it does not exist,
* $default will be returned.
Expand Down
2 changes: 1 addition & 1 deletion lib/public/iconfig.php
Expand Up @@ -47,7 +47,7 @@ public function setSystemValue($key, $value);
*
* @param string $key the key of the value, under which it was saved
* @param string $default the default value to be returned if the value isn't set
* @return string the saved value
* @return mixed the value or $default
*/
public function getSystemValue($key, $default = '');

Expand Down
38 changes: 35 additions & 3 deletions tests/lib/request.php
Expand Up @@ -9,21 +9,53 @@
class Test_Request extends PHPUnit_Framework_TestCase {

public function setUp() {
OC_Config::setValue('overwritewebroot', '/domain.tld/ownCloud');
OC::$server->getConfig()->setSystemValue('overwritewebroot', '/domain.tld/ownCloud');

OC::$server->getConfig()->setSystemValue('trusted_proxies', array());
OC::$server->getConfig()->setSystemValue('forwarded_for_headers', array());
}

public function tearDown() {
OC_Config::setValue('overwritewebroot', '');
OC::$server->getConfig()->setSystemValue('overwritewebroot', '');
OC::$server->getConfig()->setSystemValue('trusted_proxies', array());
OC::$server->getConfig()->setSystemValue('forwarded_for_headers', array());
}

public function testScriptNameOverWrite() {
$_SERVER['REMOTE_ADDR'] = '10.0.0.1';
$_SERVER["SCRIPT_FILENAME"] = __FILE__;
$_SERVER['SCRIPT_FILENAME'] = __FILE__;

$scriptName = OC_Request::scriptName();
$this->assertEquals('/domain.tld/ownCloud/tests/lib/request.php', $scriptName);
}

public function testGetRemoteAddress() {
$_SERVER['REMOTE_ADDR'] = '10.0.0.2';
$_SERVER['HTTP_X_FORWARDED'] = '10.4.0.5, 10.4.0.4';
$_SERVER['HTTP_X_FORWARDED_FOR'] = '192.168.0.233';

// Without having specified a trusted remote address
$this->assertEquals('10.0.0.2', OC_Request::getRemoteAddress());

// With specifying a trusted remote address but no trusted header
OC::$server->getConfig()->setSystemValue('trusted_proxies', array('10.0.0.2'));
$this->assertEquals('10.0.0.2', OC_Request::getRemoteAddress());

// With specifying a trusted remote address and trusted headers
OC::$server->getConfig()->setSystemValue('trusted_proxies', array('10.0.0.2'));
OC::$server->getConfig()->setSystemValue('forwarded_for_headers', array('HTTP_X_FORWARDED'));
$this->assertEquals('10.4.0.5', OC_Request::getRemoteAddress());
OC::$server->getConfig()->setSystemValue('forwarded_for_headers', array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED'));
$this->assertEquals('192.168.0.233', OC_Request::getRemoteAddress());

// With specifying multiple trusted remote addresses and trusted headers
OC::$server->getConfig()->setSystemValue('trusted_proxies', array('10.3.4.2', '10.0.0.2', '127.0.3.3'));
OC::$server->getConfig()->setSystemValue('forwarded_for_headers', array('HTTP_X_FORWARDED'));
$this->assertEquals('10.4.0.5', OC_Request::getRemoteAddress());
OC::$server->getConfig()->setSystemValue('forwarded_for_headers', array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED'));
$this->assertEquals('192.168.0.233', OC_Request::getRemoteAddress());
}

/**
* @dataProvider rawPathInfoProvider
* @param $expected
Expand Down