self::REFRESH_TIME_GENERAL) { $loginLog['common'] = ["count" => 0, "time" => \time()]; } if (empty($loginLog['usr'][$hash_user]) || \time() - $loginLog['usr'][$hash_user]['time'] > self::REFRESH_TIME_USER) { $loginLog['usr'][$hash_user] = ["count" => 0, "time" => \time()]; } if (empty($loginLog['ip'][$hash_ip]) || \time() - $loginLog['ip'][$hash_ip]['time'] > self::REFRESH_TIME_IP) { $loginLog['ip'][$hash_ip] = ["count" => 0, "time" => \time()]; } // Increase counters and update timers ++$loginLog['common']['count']; $loginLog['common']['time'] = \time(); ++$loginLog['usr'][$hash_user]['count']; $loginLog['usr'][$hash_user]['time'] = \time(); ++$loginLog['ip'][$hash_ip]['count']; $loginLog['ip'][$hash_ip]['time'] = \time(); // Update the log file \file_put_contents($logfile_common, MD_STD::json_encode($loginLog)); // Translate counters into delay multipliers $delay_multiplier_common = $loginLog['common']['count']; $delay_multiplier_per_user = $loginLog['usr'][$hash_user]['count']; $delay_multiplier_per_ip = $loginLog['ip'][$hash_ip]['count']; // Calculate delay $delay_micoseconds = \intval(self::BRUTE_FORCE_DELAY_DEFAULT * (self::BRUTE_FORCE_DELAY_MULTIPLIER_COMMON ** $delay_multiplier_common) * (self::BRUTE_FORCE_DELAY_MULTIPLIER_PER_USER ** $delay_multiplier_per_user) * (self::BRUTE_FORCE_DELAY_MULTIPLIER_PER_IP ** $delay_multiplier_per_ip)); $max_execution_microseconds = \abs((int)\ini_get("max_execution_time")) * 1000000; // Sleep \usleep(min($delay_micoseconds, \abs($max_execution_microseconds - 1000000))); if ($delay_micoseconds > \abs($max_execution_microseconds - 1000000)) { return false; } return true; } /** * Send CSP headers. * * @param array{default-src: string, connect-src: string, script-src: string, img-src: string, media-src: string, style-src: string, frame-src: string, object-src: string, base-uri: string, form-action: string, frame-ancestors?: string} $directives Directives to send. Font source is always set to 'self', and hence excluded. * @param string $frame_ancestors Frame ancestors directive. Default is to not set it. * * @return void */ public static function sendContentSecurityPolicy(array $directives, string $frame_ancestors = ""):void { $policy = 'Content-Security-Policy: default-src ' . $directives['default-src'] . '; connect-src ' . $directives['connect-src'] . '; script-src ' . $directives['script-src'] . '; img-src ' . $directives['img-src'] . '; media-src ' . $directives['media-src'] . '; style-src ' . $directives['style-src'] . '; font-src \'self\'; frame-src ' . $directives['frame-src'] . '; object-src ' . $directives['object-src'] . '; base-uri ' . $directives['base-uri'] . '; form-action ' . $directives['form-action'] . '; manifest-src \'self\'; worker-src \'self\';'; if (!empty($frame_ancestors)) { $policy .= ' frame-ancestors ' . $frame_ancestors . ';'; } header($policy); } }