log.php: neue, token-geschuetzte Ansicht fuer das Angriffsprotokoll hinzugefuegt

This commit is contained in:
2026-09-22 10:54:20 +02:00
parent 6b2f05b96b
commit 96402e8005
+96
View File
@@ -0,0 +1,96 @@
<?php
declare(strict_types=1);
/**
* Eigenständige, schlanke Protokoll-Ansicht für abgelehnte Anfragen (Angriffsprotokoll).
*
* Bewusst OHNE Einbindung des JTL-Shop-Bootstraps: diese Datei liegt im öffentlich erreichbaren
* Plugin-Verzeichnis (genau wie assets/fp-altcha.js) und wird direkt vom Webserver ausgeführt,
* nicht über die Shop-Routen. Der Zugriff wird stattdessen über einen eigenen, zufällig
* erzeugten Zugriffsschlüssel abgesichert (siehe data/fp_altcha_log_token.php, automatisch
* erzeugt nach demselben Muster wie der HMAC-Geheimschlüssel in src/Service/AltchaService.php).
*
* Aufruf: https://ihre-domain/plugins/fp_altcha_spamschutz/log.php?key=<Zugriffsschluessel>
*
* Den aktuellen Zugriffsschlüssel finden Sie in der Datei data/fp_altcha_log_token.php im
* Plugin-Verzeichnis (einmalig per FTP/Datei-Manager auslesen). Die Datei wird automatisch
* angelegt, sobald das Angriffsprotokoll in den Plugin-Einstellungen aktiviert ist.
*/
$dataDir = __DIR__ . '/data';
$tokenFile = $dataDir . '/fp_altcha_log_token.php';
$logFile = $dataDir . '/fp_altcha_attacklog.jsonl';
$expectedToken = \is_file($tokenFile) ? @include $tokenFile : null;
$providedToken = isset($_GET['key']) && \is_string($_GET['key']) ? $_GET['key'] : '';
$tokenIsValid = \is_string($expectedToken)
&& $expectedToken !== ''
&& $providedToken !== ''
&& \hash_equals($expectedToken, $providedToken);
if (!$tokenIsValid) {
\http_response_code(404);
echo 'Not found';
exit;
}
\header('Content-Type: text/html; charset=UTF-8');
\header('X-Robots-Tag: noindex, nofollow');
$entries = [];
if (\is_file($logFile)) {
$lines = @\file($logFile, \FILE_IGNORE_NEW_LINES | \FILE_SKIP_EMPTY_LINES) ?: [];
foreach (\array_reverse($lines) as $line) {
$decoded = \json_decode($line, true);
if (\is_array($decoded)) {
$entries[] = $decoded;
}
}
}
$anzahl = \count($entries);
echo '<!DOCTYPE html><html lang="de"><head><meta charset="UTF-8">'
. '<title>fp_altcha_spamschutz &ndash; Angriffsprotokoll</title>'
. '<style>'
. 'body{font-family:sans-serif;margin:2rem;background:#f7f7f7;color:#222;}'
. 'h1{font-size:1.2rem;}'
. 'table{border-collapse:collapse;width:100%;background:#fff;}'
. 'th,td{border:1px solid #ddd;padding:.4rem .6rem;font-size:.9rem;text-align:left;}'
. 'th{background:#eee;}'
. '.ja{color:#a30000;font-weight:bold;}'
. '.nein{color:#2a7d2a;}'
. '</style></head><body>';
echo '<h1>fp_altcha_spamschutz &ndash; Angriffsprotokoll ('
. $anzahl . ' Eintr&auml;ge, neueste zuerst)</h1>';
if ($anzahl === 0) {
echo '<p>Noch keine abgelehnten Anfragen protokolliert.</p>';
} else {
echo '<table><tr><th>Zeit</th><th>Formular</th><th>IP</th><th>Sicherheitspr&uuml;fung</th>'
. '<th>Namensmuster</th><th>Honeypot</th></tr>';
foreach ($entries as $entry) {
$zeit = \htmlspecialchars((string) ($entry['zeit'] ?? ''), \ENT_QUOTES, 'UTF-8');
$formular = \htmlspecialchars((string) ($entry['formular'] ?? ''), \ENT_QUOTES, 'UTF-8');
$ip = \htmlspecialchars((string) ($entry['ip'] ?? ''), \ENT_QUOTES, 'UTF-8');
$pruefung = \htmlspecialchars((string) ($entry['sicherheitspruefung'] ?? ''), \ENT_QUOTES, 'UTF-8');
$muster = !empty($entry['namensmuster']) ? '<span class="ja">ja</span>' : '<span class="nein">nein</span>';
$honeypot = !empty($entry['honeypot']) ? '<span class="ja">ja</span>' : '<span class="nein">nein</span>';
echo '<tr>'
. '<td>' . $zeit . '</td>'
. '<td>' . $formular . '</td>'
. '<td>' . $ip . '</td>'
. '<td>' . $pruefung . '</td>'
. '<td>' . $muster . '</td>'
. '<td>' . $honeypot . '</td>'
. '</tr>';
}
echo '</table>';
}
echo '</body></html>';