From c5395df243b01b6ecbc3611b2d1a584a5358f0ba Mon Sep 17 00:00:00 2001 From: Shish Date: Thu, 4 Jan 2024 14:50:36 +0000 Subject: [PATCH] [core] trust x-forwarded-for from trusted proxies, see #800 --- core/sys_config.php | 2 +- core/util.php | 38 +++++++++++++++++++++++++------------- tests/defines.php | 2 +- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/core/sys_config.php b/core/sys_config.php index 2f5cb0c2..1ed2cd49 100644 --- a/core/sys_config.php +++ b/core/sys_config.php @@ -37,4 +37,4 @@ _d("EXTRA_EXTS", ""); // string optional extra extensions _d("BASE_HREF", null); // string force a specific base URL (default is auto-detect) _d("TRACE_FILE", null); // string file to log performance data into _d("TRACE_THRESHOLD", 0.0); // float log pages which take more time than this many seconds -_d("REVERSE_PROXY_X_HEADERS", false); // boolean get request IPs from "X-Real-IP" and protocol from "X-Forwarded-Proto" HTTP headers +_d("TRUSTED_PROXIES", []); // array trust "X-Real-IP" / "X-Forwarded-For" / "X-Forwarded-Proto" headers from these IP ranges diff --git a/core/util.php b/core/util.php index 9c695e7d..ba18d8bc 100644 --- a/core/util.php +++ b/core/util.php @@ -54,7 +54,7 @@ function contact_link(): ?string function is_https_enabled(): bool { // check forwarded protocol - if (REVERSE_PROXY_X_HEADERS && !empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') { + if (is_trusted_proxy() && !empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') { $_SERVER['HTTPS'] = 'on'; } return (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off'); @@ -148,25 +148,37 @@ function check_im_version(): int return (empty($convert_check) ? 0 : 1); } -/** - * Get request IP - */ - -function get_remote_addr() +function is_trusted_proxy(): bool { - return $_SERVER['REMOTE_ADDR']; + $ra = $_SERVER['REMOTE_ADDR'] ?? "0.0.0.0"; + foreach(TRUSTED_PROXIES as $proxy) { + if(ip_in_range($ra, $proxy)) { + return true; + } + } + return false; } + /** * Get real IP if behind a reverse proxy */ - function get_real_ip() { - $ip = get_remote_addr(); - if (REVERSE_PROXY_X_HEADERS && isset($_SERVER['HTTP_X_REAL_IP'])) { - $ip = $_SERVER['HTTP_X_REAL_IP']; - if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) { - $ip = "0.0.0.0"; + $ip = $_SERVER['REMOTE_ADDR']; + + if(is_trusted_proxy()) { + if (isset($_SERVER['HTTP_X_REAL_IP'])) { + if(filter_var($ip, FILTER_VALIDATE_IP)) { + $ip = $_SERVER['HTTP_X_REAL_IP']; + } + } + + if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { + $ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); + $last_ip = $ips[count($ips) - 1]; + if(filter_var($last_ip, FILTER_VALIDATE_IP)) { + $ip = $last_ip; + } } } diff --git a/tests/defines.php b/tests/defines.php index dc6ad864..5744f427 100644 --- a/tests/defines.php +++ b/tests/defines.php @@ -21,4 +21,4 @@ define("TIMEZONE", 'UTC'); define("BASE_HREF", "/test"); define("CLI_LOG_LEVEL", 50); define("STATSD_HOST", null); -define("REVERSE_PROXY_X_HEADERS", false); +define("TRUSTED_PROXIES", []);