CVE-2023-2666 (PHP, published 2023-05-12T01:15Z)
Description: value: Allocation of Resources Without Limits or Throttling in GitHub repository froxlor/froxlor prior to 2.0.16.
Severity: nan (CVSS v3 base score: 7.5)
Weakness: CWE-770 \u2014 Allocation of Resources Without Limits or Throttling
The product allocates a reusable resource or group of resources on behalf of an actor without imposing any restrictions on the size or number of resources that can be allocated, in violation of the intended security policy for that actor.
Repository: https://github.com/froxlor/froxlor
Files changed:
actions/admin/settings/110.accounts.php
install/froxlor.sql.php
install/install.php
install/updates/froxlor/update_2.x.inc.php
lib/Froxlor/Api/Api.php
lib/Froxlor/Cli/CliCommand.php
lib/Froxlor/Froxlor.php
lib/Froxlor/Http/RateLimiter.php
lib/Froxlor/PhpHelper.php
lib/init.php
lng/de.lng.php
lng/en.lng.php
Commit message: introduce http-request rate-limit; smaller fixes

Signed-off-by: Michael Kaufmann <d00p@froxlor.org>


Vulnerable code:
	('panel', 'db_version', '202303150');
			'this',
	const DBVERSION = '202303150';
					$str .= self::tabPrefix($depth, "'{$key}' => '{$value}',\n");

Fixed code:
				'system_req_limit_per_interval' => [
					'label' => lng('serversettings.req_limit_per_interval'),
					'settinggroup' => 'system',
					'varname' => 'req_limit_per_interval',
					'type' => 'number',
					'min' => 30,
					'default' => 60,
					'save_method' => 'storeSettingField',
					'advanced_mode' => true
				],
				'system_req_limit_interval' => [
					'label' => lng('serversettings.req_limit_interval'),
					'settinggroup' => 'system',
					'varname' => 'req_limit_interval',
					'type' => 'number',
					'min' => 5,
					'default' => 60,
					'save_method' => 'storeSettingField',
					'advanced_mode' => true
				],
	('system', 'req_limit_per_interval', 60),
	('system', 'req_limit_interval', 60),
	('panel', 'db_version', '202304260');
use Froxlor\Http\RateLimiter;
RateLimiter::run(true);

if (Froxlor::isDatabaseVersion('202303150')) {
	Update::showUpdateStep("Adding new request rate limit settings");
	Settings::AddNew("system.req_limit_per_interval", "60");
	Settings::AddNew("system.req_limit_interval", "60");
	Update::lastStepStatus(0);

	Froxlor::updateToDbVersion('202304260');
}
use Froxlor\Http\RateLimiter;

		RateLimiter::run();
			$this,
	const DBVERSION = '202304260';
<?php

namespace Froxlor\Http;

class RateLimiter
{
	private static int $limit_per_interval = 60;
	private static int $reset_time = 0;

	public static function run(bool $install_mode = false)
	{
		// default interval = 60 sec
		self::$reset_time = time() + 60;

		if (!$install_mode) {
			self::$limit_per_interval = Settings::Get('system.req_limit_per_interval');
			self::$reset_time = time() + Settings::Get('system.req_limit_interval');
		}

		// Get the remaining requests and reset time from the headers
		$remaining = isset($_SESSION['HTTP_X_RATELIMIT_REMAINING']) ? (int)$_SESSION['HTTP_X_RATELIMIT_REMAINING'] : self::$limit_per_interval;
		$reset = isset($_SESSION['HTTP_X_RATELIMIT_RESET']) ? (int)$_SESSION['HTTP_X_RATELIMIT_RESET'] : self::$reset_time;

		// check if reset time is due
		if (time() > $reset) {
			$remaining = self::$limit_per_interval;
			$reset = self::$reset_time;
		}

		// If we've hit the limit, return an error
		if ($remaining <= 0) {
			header('HTTP/1.1 429 Too Many Requests');
			header("Retry-After: $reset");
			exit();
		}

		// Decrement the remaining requests and update the headers
		$remaining--;
		$_SESSION['HTTP_X_RATELIMIT_REMAINING'] = $remaining;
		$_SESSION['HTTP_X_RATELIMIT_RESET'] = $reset;

		header("X-RateLimit-Limit: " . self::$limit_per_interval);
		header("X-RateLimit-Remaining: " . $remaining);
		header("X-RateLimit-Reset: " . $reset);
	}
}
					if ($key == 'password') {
						// special case for passwords (nowdoc)
						$str .= self::tabPrefix($depth, "'{$key}' => <<<'EOT'\n{$value}\nEOT,\n");
					} else {
						$str .= self::tabPrefix($depth, "'{$key}' => '{$value}',\n");
					}
use Froxlor\Http\RateLimiter;
RateLimiter::run();
		'req_limit_per_interval' => [
			'title' => 'Anzahl der HTTP-Anfragen pro Intervall',
			'description' => 'Erlaubte Anzahl von HTTP-Anfragen pro Intervall (siehe unten) auf froxlor, Standard ist "60"',
		],
		'req_limit_interval' => [
			'title' => 'Rate-Limit-Intervall',
			'description' => 'Specify the time in seconds for the number of HTTP requests, default is "60"',
		],
		'req_limit_per_interval' => [
			'title' => 'Number of HTTP requests per interval',
			'description' => 'Limit the number of HTTP requests per interval (see below) to froxlor, default is "60"',
		],
		'req_limit_interval' => [
			'title' => 'Rate-limit interval',
			'description' => 'Zeit in Sekunden für die maximale Anzahl von HTTP-Anfragen, Standard ist "60".',
		],