Merge pull request #13150 from nextcloud/backport/13116/stable15

[stable15] Only trust the X-FORWARDED-HOST header for trusted proxies
This commit is contained in:
Roeland Jago Douma 2018-12-19 12:59:20 +01:00 committed by GitHub
commit f9707abc0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 98 additions and 55 deletions

View File

@ -691,7 +691,7 @@ class Request implements \ArrayAccess, \Countable, IRequest {
return $this->config->getSystemValue('overwriteprotocol');
}
if (isset($this->server['HTTP_X_FORWARDED_PROTO'])) {
if ($this->fromTrustedProxy() && isset($this->server['HTTP_X_FORWARDED_PROTO'])) {
if (strpos($this->server['HTTP_X_FORWARDED_PROTO'], ',') !== false) {
$parts = explode(',', $this->server['HTTP_X_FORWARDED_PROTO']);
$proto = strtolower(trim($parts[0]));
@ -862,7 +862,7 @@ class Request implements \ArrayAccess, \Countable, IRequest {
*/
public function getInsecureServerHost(): string {
$host = 'localhost';
if (isset($this->server['HTTP_X_FORWARDED_HOST'])) {
if ($this->fromTrustedProxy() && isset($this->server['HTTP_X_FORWARDED_HOST'])) {
if (strpos($this->server['HTTP_X_FORWARDED_HOST'], ',') !== false) {
$parts = explode(',', $this->server['HTTP_X_FORWARDED_HOST']);
$host = trim(current($parts));
@ -924,4 +924,10 @@ class Request implements \ArrayAccess, \Countable, IRequest {
return null;
}
private function fromTrustedProxy(): bool {
$remoteAddress = isset($this->server['REMOTE_ADDR']) ? $this->server['REMOTE_ADDR'] : '';
$trustedProxies = $this->config->getSystemValue('trusted_proxies', []);
return \is_array($trustedProxies) && $this->isTrustedProxy($trustedProxies, $remoteAddress);
}
}

View File

@ -715,15 +715,20 @@ class RequestTest extends \Test\TestCase {
public function testGetServerProtocolWithProtoValid() {
$this->config
->expects($this->exactly(2))
->method('getSystemValue')
->with('overwriteprotocol')
->will($this->returnValue(''));
->will($this->returnCallback(function($key, $default) {
if ($key === 'trusted_proxies') {
return ['1.2.3.4'];
}
return $default;
}));
$requestHttps = new Request(
[
'server' => [
'HTTP_X_FORWARDED_PROTO' => 'HtTpS'
'HTTP_X_FORWARDED_PROTO' => 'HtTpS',
'REMOTE_ADDR' => '1.2.3.4',
],
],
$this->secureRandom,
@ -734,7 +739,8 @@ class RequestTest extends \Test\TestCase {
$requestHttp = new Request(
[
'server' => [
'HTTP_X_FORWARDED_PROTO' => 'HTTp'
'HTTP_X_FORWARDED_PROTO' => 'HTTp',
'REMOTE_ADDR' => '1.2.3.4',
],
],
$this->secureRandom,
@ -750,10 +756,10 @@ class RequestTest extends \Test\TestCase {
public function testGetServerProtocolWithHttpsServerValueOn() {
$this->config
->expects($this->once())
->method('getSystemValue')
->with('overwriteprotocol')
->will($this->returnValue(''));
->will($this->returnCallback(function($key, $default) {
return $default;
}));
$request = new Request(
[
@ -771,10 +777,10 @@ class RequestTest extends \Test\TestCase {
public function testGetServerProtocolWithHttpsServerValueOff() {
$this->config
->expects($this->once())
->method('getSystemValue')
->with('overwriteprotocol')
->will($this->returnValue(''));
->will($this->returnCallback(function($key, $default) {
return $default;
}));
$request = new Request(
[
@ -792,10 +798,10 @@ class RequestTest extends \Test\TestCase {
public function testGetServerProtocolWithHttpsServerValueEmpty() {
$this->config
->expects($this->once())
->method('getSystemValue')
->with('overwriteprotocol')
->will($this->returnValue(''));
->will($this->returnCallback(function($key, $default) {
return $default;
}));
$request = new Request(
[
@ -813,10 +819,10 @@ class RequestTest extends \Test\TestCase {
public function testGetServerProtocolDefault() {
$this->config
->expects($this->once())
->method('getSystemValue')
->with('overwriteprotocol')
->will($this->returnValue(''));
->will($this->returnCallback(function($key, $default) {
return $default;
}));
$request = new Request(
[],
@ -830,15 +836,20 @@ class RequestTest extends \Test\TestCase {
public function testGetServerProtocolBehindLoadBalancers() {
$this->config
->expects($this->once())
->method('getSystemValue')
->with('overwriteprotocol')
->will($this->returnValue(''));
->will($this->returnCallback(function($key, $default) {
if ($key === 'trusted_proxies') {
return ['1.2.3.4'];
}
return $default;
}));
$request = new Request(
[
'server' => [
'HTTP_X_FORWARDED_PROTO' => 'https,http,http'
'HTTP_X_FORWARDED_PROTO' => 'https,http,http',
'REMOTE_ADDR' => '1.2.3.4',
],
],
$this->secureRandom,
@ -1025,12 +1036,23 @@ class RequestTest extends \Test\TestCase {
}
public function testInsecureServerHostHttpFromForwardedHeaderSingle() {
$this->config
->method('getSystemValue')
->will($this->returnCallback(function($key, $default) {
if ($key === 'trusted_proxies') {
return ['1.2.3.4'];
}
return $default;
}));
$request = new Request(
[
'server' => [
'SERVER_NAME' => 'from.server.name:8080',
'HTTP_HOST' => 'from.host.header:8080',
'HTTP_X_FORWARDED_HOST' => 'from.forwarded.host:8080',
'REMOTE_ADDR' => '1.2.3.4',
]
],
$this->secureRandom,
@ -1043,12 +1065,23 @@ class RequestTest extends \Test\TestCase {
}
public function testInsecureServerHostHttpFromForwardedHeaderStacked() {
$this->config
->method('getSystemValue')
->will($this->returnCallback(function($key, $default) {
if ($key === 'trusted_proxies') {
return ['1.2.3.4'];
}
return $default;
}));
$request = new Request(
[
'server' => [
'SERVER_NAME' => 'from.server.name:8080',
'HTTP_HOST' => 'from.host.header:8080',
'HTTP_X_FORWARDED_HOST' => 'from.forwarded.host2:8080,another.one:9000',
'REMOTE_ADDR' => '1.2.3.4',
]
],
$this->secureRandom,
@ -1062,20 +1095,16 @@ class RequestTest extends \Test\TestCase {
public function testGetServerHostWithOverwriteHost() {
$this->config
->expects($this->at(0))
->method('getSystemValue')
->with('overwritehost')
->will($this->returnValue('my.overwritten.host'));
$this->config
->expects($this->at(1))
->method('getSystemValue')
->with('overwritecondaddr')
->will($this->returnValue(''));
$this->config
->expects($this->at(2))
->method('getSystemValue')
->with('overwritehost')
->will($this->returnValue('my.overwritten.host'));
->will($this->returnCallback(function($key, $default) {
if ($key === 'overwritecondaddr') {
return '';
} else if ($key === 'overwritehost') {
return 'my.overwritten.host';
}
return $default;
}));
$request = new Request(
[],
@ -1090,15 +1119,22 @@ class RequestTest extends \Test\TestCase {
public function testGetServerHostWithTrustedDomain() {
$this->config
->expects($this->at(3))
->method('getSystemValue')
->with('trusted_domains')
->will($this->returnValue(['my.trusted.host']));
->will($this->returnCallback(function($key, $default) {
if ($key === 'trusted_proxies') {
return ['1.2.3.4'];
} else if ($key === 'trusted_domains') {
return ['my.trusted.host'];
}
return $default;
}));
$request = new Request(
[
'server' => [
'HTTP_X_FORWARDED_HOST' => 'my.trusted.host',
'REMOTE_ADDR' => '1.2.3.4',
],
],
$this->secureRandom,
@ -1112,20 +1148,22 @@ class RequestTest extends \Test\TestCase {
public function testGetServerHostWithUntrustedDomain() {
$this->config
->expects($this->at(3))
->method('getSystemValue')
->with('trusted_domains')
->will($this->returnValue(['my.trusted.host']));
$this->config
->expects($this->at(4))
->method('getSystemValue')
->with('trusted_domains')
->will($this->returnValue(['my.trusted.host']));
->will($this->returnCallback(function($key, $default) {
if ($key === 'trusted_proxies') {
return ['1.2.3.4'];
} else if ($key === 'trusted_domains') {
return ['my.trusted.host'];
}
return $default;
}));
$request = new Request(
[
'server' => [
'HTTP_X_FORWARDED_HOST' => 'my.untrusted.host',
'REMOTE_ADDR' => '1.2.3.4',
],
],
$this->secureRandom,
@ -1139,20 +1177,19 @@ class RequestTest extends \Test\TestCase {
public function testGetServerHostWithNoTrustedDomain() {
$this->config
->expects($this->at(3))
->method('getSystemValue')
->with('trusted_domains')
->will($this->returnValue([]));
$this->config
->expects($this->at(4))
->method('getSystemValue')
->with('trusted_domains')
->will($this->returnValue([]));
->will($this->returnCallback(function($key, $default) {
if ($key === 'trusted_proxies') {
return ['1.2.3.4'];
}
return $default;
}));
$request = new Request(
[
'server' => [
'HTTP_X_FORWARDED_HOST' => 'my.untrusted.host',
'REMOTE_ADDR' => '1.2.3.4',
],
],
$this->secureRandom,