AltchaService: Angriffsprotokoll (Datei-Log + Zugriffsschluessel) hinzugefuegt
This commit is contained in:
@@ -102,6 +102,120 @@ class AltchaService
|
||||
return (int) $this->getConfigValue('fp_altcha_honeypot_threshold', '50');
|
||||
}
|
||||
|
||||
/**
|
||||
* Das Angriffsprotokoll ist unabhaengig vom (nur fuer Tests gedachten) Debug-Logging und
|
||||
* standardmaessig aktiv: es haelt fortlaufend die zuletzt abgelehnten Anfragen fest.
|
||||
*/
|
||||
public function isAttackLogEnabled(): bool
|
||||
{
|
||||
return $this->getConfigValue('fp_altcha_attack_log', 'on') === 'on';
|
||||
}
|
||||
|
||||
/**
|
||||
* Haengt einen abgelehnten Versuch an die rotierende Protokolldatei an (siehe log.php fuer
|
||||
* die Ansicht). Bewusst komplett fehlertolerant: schlaegt das Schreiben fehl (z. B. keine
|
||||
* Schreibrechte), wird das still ignoriert -- die eigentliche Formularpruefung darf davon
|
||||
* nie beeintraechtigt werden.
|
||||
*
|
||||
* @param array<string, mixed> $entry
|
||||
*/
|
||||
public function appendAttackLogEntry(array $entry): void
|
||||
{
|
||||
try {
|
||||
$dir = $this->pluginDir . '/data';
|
||||
$file = $dir . '/fp_altcha_attacklog.jsonl';
|
||||
|
||||
if (!\is_dir($dir)) {
|
||||
@\mkdir($dir, 0755, true);
|
||||
}
|
||||
|
||||
$line = \json_encode($entry, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE);
|
||||
if (!\is_string($line)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@\file_put_contents($file, $line . "\n", \FILE_APPEND | \LOCK_EX);
|
||||
|
||||
$this->trimAttackLog($file);
|
||||
} catch (\Throwable $e) {
|
||||
// Protokollieren ist ein Zusatzfeature -- ein Fehler hier darf niemals die eigentliche
|
||||
// Formularpruefung stoeren.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Kuerzt die Protokolldatei auf die konfigurierte Hoechstanzahl an Eintraegen. Laeuft nur
|
||||
* mit geringer Wahrscheinlichkeit bei jedem Aufruf (statt immer), um bei vielen gleichzeitigen
|
||||
* Anfragen nicht staendig die komplette Datei einlesen zu muessen.
|
||||
*/
|
||||
private function trimAttackLog(string $file): void
|
||||
{
|
||||
if (\random_int(1, 20) !== 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!\is_file($file)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$lines = @\file($file, \FILE_IGNORE_NEW_LINES | \FILE_SKIP_EMPTY_LINES);
|
||||
if ($lines === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$max = $this->getAttackLogMaxEntries();
|
||||
if (\count($lines) <= $max) {
|
||||
return;
|
||||
}
|
||||
|
||||
$trimmed = \array_slice($lines, -$max);
|
||||
@\file_put_contents($file, \implode("\n", $trimmed) . "\n", \LOCK_EX);
|
||||
}
|
||||
|
||||
private function getAttackLogMaxEntries(): int
|
||||
{
|
||||
$value = (int) $this->getConfigValue('fp_altcha_attack_log_max', '300');
|
||||
if ($value < 20 || $value > 5000) {
|
||||
return 300;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Liefert den Zugriffsschluessel fuer die eigenstaendige Protokoll-Ansicht (log.php). Wird
|
||||
* beim allerersten Bedarf automatisch zufaellig erzeugt und in einer eigenen Datei im
|
||||
* Plugin-Verzeichnis gespeichert -- exakt nach demselben Muster wie der HMAC-Geheimschluessel
|
||||
* (siehe getOrCreateAutoSecret()).
|
||||
*/
|
||||
public function getLogViewToken(): string
|
||||
{
|
||||
$dir = $this->pluginDir . '/data';
|
||||
$file = $dir . '/fp_altcha_log_token.php';
|
||||
|
||||
if (\is_file($file)) {
|
||||
$value = include $file;
|
||||
if (\is_string($value) && $value !== '') {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
$token = \bin2hex(\random_bytes(24));
|
||||
|
||||
if (!\is_dir($dir)) {
|
||||
@\mkdir($dir, 0755, true);
|
||||
}
|
||||
|
||||
@\file_put_contents(
|
||||
$file,
|
||||
"<?php\n\n// Automatisch erzeugter Zugriffsschluessel fuer die Protokoll-Ansicht (log.php) --"
|
||||
. " nicht manuell bearbeiten.\n"
|
||||
. 'return ' . \var_export($token, true) . ";\n"
|
||||
);
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erzeugt eine neue Prüfung und liefert sie als Array, das 1:1 als JSON in die Seite
|
||||
* eingebettet werden kann (siehe TemplateHandler).
|
||||
|
||||
Reference in New Issue
Block a user