ForwardedForHeaders.php 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace OCA\Settings\SetupChecks;
  8. use OCP\IConfig;
  9. use OCP\IL10N;
  10. use OCP\IRequest;
  11. use OCP\IURLGenerator;
  12. use OCP\SetupCheck\ISetupCheck;
  13. use OCP\SetupCheck\SetupResult;
  14. class ForwardedForHeaders implements ISetupCheck {
  15. public function __construct(
  16. private IL10N $l10n,
  17. private IConfig $config,
  18. private IURLGenerator $urlGenerator,
  19. private IRequest $request,
  20. ) {
  21. }
  22. public function getCategory(): string {
  23. return 'security';
  24. }
  25. public function getName(): string {
  26. return $this->l10n->t('Forwarded for headers');
  27. }
  28. public function run(): SetupResult {
  29. $trustedProxies = $this->config->getSystemValue('trusted_proxies', []);
  30. $remoteAddress = $this->request->getHeader('REMOTE_ADDR');
  31. $detectedRemoteAddress = $this->request->getRemoteAddress();
  32. if (!\is_array($trustedProxies)) {
  33. return SetupResult::error($this->l10n->t('Your "trusted_proxies" setting is not correctly set, it should be an array.'));
  34. }
  35. foreach ($trustedProxies as $proxy) {
  36. $addressParts = explode('/', $proxy, 2);
  37. if (filter_var($addressParts[0], FILTER_VALIDATE_IP) === false || !ctype_digit($addressParts[1] ?? '24')) {
  38. return SetupResult::error(
  39. $this->l10n->t('Your "trusted_proxies" setting is not correctly set, it should be an array of IP addresses - optionally with range in CIDR notation.'),
  40. $this->urlGenerator->linkToDocs('admin-reverse-proxy'),
  41. );
  42. }
  43. }
  44. if (($remoteAddress === '') && ($detectedRemoteAddress === '')) {
  45. if (\OC::$CLI) {
  46. /* We were called from CLI */
  47. return SetupResult::info($this->l10n->t('Your remote address could not be determined.'));
  48. } else {
  49. /* Should never happen */
  50. return SetupResult::error($this->l10n->t('Your remote address could not be determined.'));
  51. }
  52. }
  53. if (empty($trustedProxies) && $this->request->getHeader('X-Forwarded-Host') !== '') {
  54. return SetupResult::error(
  55. $this->l10n->t('The reverse proxy header configuration is incorrect. This is a security issue and can allow an attacker to spoof their IP address as visible to the Nextcloud.'),
  56. $this->urlGenerator->linkToDocs('admin-reverse-proxy')
  57. );
  58. }
  59. if (\in_array($remoteAddress, $trustedProxies, true) && ($remoteAddress !== '127.0.0.1')) {
  60. if ($remoteAddress !== $detectedRemoteAddress) {
  61. /* Remote address was successfuly fixed */
  62. return SetupResult::success($this->l10n->t('Your IP address was resolved as %s', [$detectedRemoteAddress]));
  63. } else {
  64. return SetupResult::warning(
  65. $this->l10n->t('The reverse proxy header configuration is incorrect, or you are accessing Nextcloud from a trusted proxy. If not, this is a security issue and can allow an attacker to spoof their IP address as visible to the Nextcloud.'),
  66. $this->urlGenerator->linkToDocs('admin-reverse-proxy')
  67. );
  68. }
  69. }
  70. /* Either not enabled or working correctly */
  71. return SetupResult::success();
  72. }
  73. }