Skip to content

Commit dfca100

Browse files
authored
Merge pull request #41529 from nextcloud/backport/41526/stable25
[stable25] Reverse X-Forwarded-For list to read the correct proxy remote address
2 parents a4b99b4 + 64ca62d commit dfca100

File tree

2 files changed

+40
-8
lines changed

2 files changed

+40
-8
lines changed

lib/private/AppFramework/Http/Request.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -605,16 +605,22 @@ public function getRemoteAddress(): string {
605605
// only have one default, so we cannot ship an insecure product out of the box
606606
]);
607607

608-
foreach ($forwardedForHeaders as $header) {
608+
// Read the x-forwarded-for headers and values in reverse order as per
609+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For#selecting_an_ip_address
610+
foreach (array_reverse($forwardedForHeaders) as $header) {
609611
if (isset($this->server[$header])) {
610-
foreach (explode(',', $this->server[$header]) as $IP) {
612+
foreach (array_reverse(explode(',', $this->server[$header])) as $IP) {
611613
$IP = trim($IP);
612614

613615
// remove brackets from IPv6 addresses
614616
if (strpos($IP, '[') === 0 && substr($IP, -1) === ']') {
615617
$IP = substr($IP, 1, -1);
616618
}
617619

620+
if ($this->isTrustedProxy($trustedProxies, $IP)) {
621+
continue;
622+
}
623+
618624
if (filter_var($IP, FILTER_VALIDATE_IP) !== false) {
619625
return $IP;
620626
}

tests/lib/AppFramework/Http/RequestTest.php

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,33 @@ public function testGetRemoteAddressWithSingleTrustedRemote() {
445445
$this->stream
446446
);
447447

448-
$this->assertSame('10.4.0.5', $request->getRemoteAddress());
448+
$this->assertSame('10.4.0.4', $request->getRemoteAddress());
449+
}
450+
451+
public function testGetRemoteAddressWithMultipleTrustedRemotes() {
452+
$this->config
453+
->expects($this->exactly(2))
454+
->method('getSystemValue')
455+
->willReturnMap([
456+
['trusted_proxies', [], ['10.0.0.2', '::1']],
457+
['forwarded_for_headers', ['HTTP_X_FORWARDED_FOR'], ['HTTP_X_FORWARDED']],
458+
]);
459+
460+
$request = new Request(
461+
[
462+
'server' => [
463+
'REMOTE_ADDR' => '10.0.0.2',
464+
'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4, ::1',
465+
'HTTP_X_FORWARDED_FOR' => '192.168.0.233'
466+
],
467+
],
468+
$this->requestId,
469+
$this->config,
470+
$this->csrfTokenManager,
471+
$this->stream
472+
);
473+
474+
$this->assertSame('10.4.0.4', $request->getRemoteAddress());
449475
}
450476

451477
public function testGetRemoteAddressIPv6WithSingleTrustedRemote() {
@@ -474,7 +500,7 @@ public function testGetRemoteAddressIPv6WithSingleTrustedRemote() {
474500
$this->stream
475501
);
476502

477-
$this->assertSame('10.4.0.5', $request->getRemoteAddress());
503+
$this->assertSame('10.4.0.4', $request->getRemoteAddress());
478504
}
479505

480506
public function testGetRemoteAddressVerifyPriorityHeader() {
@@ -487,9 +513,9 @@ public function testGetRemoteAddressVerifyPriorityHeader() {
487513
)-> willReturnOnConsecutiveCalls(
488514
['10.0.0.2'],
489515
[
490-
'HTTP_CLIENT_IP',
491-
'HTTP_X_FORWARDED_FOR',
492516
'HTTP_X_FORWARDED',
517+
'HTTP_X_FORWARDED_FOR',
518+
'HTTP_CLIENT_IP',
493519
],
494520
);
495521

@@ -520,9 +546,9 @@ public function testGetRemoteAddressIPv6VerifyPriorityHeader() {
520546
)-> willReturnOnConsecutiveCalls(
521547
['2001:db8:85a3:8d3:1319:8a2e:370:7348'],
522548
[
523-
'HTTP_CLIENT_IP',
549+
'HTTP_X_FORWARDED',
524550
'HTTP_X_FORWARDED_FOR',
525-
'HTTP_X_FORWARDED'
551+
'HTTP_CLIENT_IP',
526552
],
527553
);
528554

0 commit comments

Comments
 (0)