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');
|
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
|
* Erzeugt eine neue Prüfung und liefert sie als Array, das 1:1 als JSON in die Seite
|
||||||
* eingebettet werden kann (siehe TemplateHandler).
|
* eingebettet werden kann (siehe TemplateHandler).
|
||||||
|
|||||||
Reference in New Issue
Block a user