From e7689459f25663e00b4f5814a3608872ff36b582 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 30 Jul 2023 12:59:18 +0200 Subject: Rework trusted proxies (#5549) * Rework trusted proxies Fix https://github.com/FreshRSS/FreshRSS/issues/5502 Follow-up of https://github.com/FreshRSS/FreshRSS/pull/3226 New environment variable `TRUSTED_PROXY`: set to 0 to disable, or to a list of trusted IP ranges compatible with https://httpd.apache.org/docs/current/mod/mod_remoteip.html#remoteiptrustedproxy New internal environment variable `CONN_REMOTE_ADDR` to remember the true IP address of the connection (e.g. last proxy), even when using mod_remoteip. Current working setups should not observe any significant change. * Minor whitespace * Safer trusted sources during install Rework of https://github.com/FreshRSS/FreshRSS/pull/5358 https://github.com/FreshRSS/FreshRSS/issues/5357 * Minor readme --- lib/lib_rss.php | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/lib_rss.php b/lib/lib_rss.php index ec00513e2..9d995c6d6 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -653,21 +653,43 @@ function checkCIDR(string $ip, string $range): bool { } /** - * Check if the client is allowed to send unsafe headers - * This uses the REMOTE_ADDR header to determine the sender’s IP - * and the configuration option "trusted_sources" to get an array of the authorized ranges - * + * Use CONN_REMOTE_ADDR (if available, to be robust even when using Apache mod_remoteip) or REMOTE_ADDR environment variable to determine the connection IP. + */ +function connectionRemoteAddress(): string { + $remoteIp = $_SERVER['CONN_REMOTE_ADDR'] ?? ''; + if ($remoteIp == '') { + $remoteIp = $_SERVER['REMOTE_ADDR'] ?? ''; + } + if ($remoteIp == 0) { + $remoteIp = ''; + } + return $remoteIp; +} + +/** + * Check if the client (e.g. last proxy) is allowed to send unsafe headers. + * This uses the `TRUSTED_PROXY` environment variable or the `trusted_sources` configuration option to get an array of the authorized ranges, + * The connection IP is obtained from the `CONN_REMOTE_ADDR` (if available, to be robust even when using Apache mod_remoteip) or `REMOTE_ADDR` environment variables. * @return bool, true if the sender’s IP is in one of the ranges defined in the configuration, else false */ function checkTrustedIP(): bool { if (FreshRSS_Context::$system_conf === null) { return false; } - if (!empty($_SERVER['REMOTE_ADDR'])) { - foreach (FreshRSS_Context::$system_conf->trusted_sources as $cidr) { - if (checkCIDR($_SERVER['REMOTE_ADDR'], $cidr)) { - return true; - } + $remoteIp = connectionRemoteAddress(); + if ($remoteIp === '') { + return false; + } + $trusted = getenv('TRUSTED_PROXY'); + if ($trusted != 0 && is_string($trusted)) { + $trusted = preg_split('/\s+/', $trusted, -1, PREG_SPLIT_NO_EMPTY); + } + if (empty($trusted)) { + $trusted = FreshRSS_Context::$system_conf->trusted_sources; + } + foreach (FreshRSS_Context::$system_conf->trusted_sources as $cidr) { + if (checkCIDR($remoteIp, $cidr)) { + return true; } } return false; -- cgit v1.2.3