WBCE CMS Forum

WBCE CMS – Way Better Content Editing.

You are not logged in.

#1 23.11.2024 11:44:54

kleo
Member

Access deny

Moin!

Heutzutage sind die "unerwünschten Gäste" einer Webseite schon die Regel.

Ihre Webseitenaufrufe veränderen unter anderem die eigentliche Besucherstatistik. Man kann bestimmte URI´s sperren und damit auch deren Aufrufe in der Statistik. Die normale Aufrufe (sprich von den existierenden Seiten) werden aber weiter auch von diesen "Besucher" gezählt.

In diesem Zusammenhabf ist mir eine Frage aufgefallen.

Wäre es irgendwie möglich nach Aufruf einer URI mit bestimmten Wörter (Zeichenkomnination) die IP-Adresse des Benutzers für eine bestimmte Zeit sperren?

So was, wie bei mehreren Versuchen die falschen Logindaten einzugeben wird die IP-Adresse für eine bestimmte Zeit gesperret.

Offline

#2 24.11.2024 19:09:42

florian
Administrator

Re: Access deny

Interessante Idee, ich kenne das von Wordfence (einem Plugin für Würgpress).
Sprich doch mal Ruud direkt darauf an. Sein 404-Modul loggt bereits verdächtige Anfragen, vielleicht lässt sich das entsprechend erweitern.
Ruud freut sich übrigens auch über Nutzung seines Paypal-Spendenlinks.


Sorgen sind wie Nudeln: man macht sich meist zu viele.

Offline

#3 28.11.2024 13:04:12

mrbaseman
Developer

Re: Access deny

Für den Backend-Login ist ja schon eine IP-basierte Sperre drin, die bei Fehlversuchen einen Timeout hoch setzt.
Aber diese IPs dann für den Aufruf beliebiger Seiten auch sprren zu können, wäre eine interessante Erweiterung.
Das müsste man vermutlich in der Frontend-Klasse mit verdrahten, und für diese gesperrten IPs halt einen 401 Status code ausgeben.

Offline

#4 03.12.2024 11:59:21

kleo
Member

Re: Access deny

Moin!

Ich habe an einer Lösung gebastellt und scheinbar eine funktionierende Methode gefunden.

Es sind zwei neue Dateien, die im root der WBCE-Installation platziert sollen:

1. security_check.php - die ist für Sperrung
2. banned_ips.json - da werden die gesperrten IP-Adressen provisorisch gespeichert.

security_check.php:

[== PHP ==]
<?php
// Datei: security_check.php

// Einstellungen
$forbiddenPatterns = ['/test123/', '/hack/', '/badword/']; // Verbotene Muster (Regex)
$banDuration = 60; // Sperrdauer in Sekunden (z. B. 60 s =1 Minute)

// Funktion, um die IP-Adresse des Besuchers zu ermitteln
function getVisitorIP() {
    return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
}

// Funktion, um eine IP-Adresse zu sperren
function banIP($ip, $duration) {
    $bannedIPsFile = 'banned_ips.json'; // Datei zur Speicherung der gesperrten IPs
    $bannedIPs = [];

    // Lade bestehende Sperren
    if (file_exists($bannedIPsFile)) {
        $bannedIPs = json_decode(file_get_contents($bannedIPsFile), true);
    }

    // Füge die aktuelle Sperre hinzu
    $bannedIPs[$ip] = time() + $duration;

    // Speichere die Sperren zurück in die Datei
    file_put_contents($bannedIPsFile, json_encode($bannedIPs));
}

// Funktion, um zu prüfen, ob eine IP gesperrt ist
function isIPBanned($ip) {
    $bannedIPsFile = 'banned_ips.json'; // Datei zur Speicherung der gesperrten IPs

    if (!file_exists($bannedIPsFile)) {
        return false;
    }

    $bannedIPs = json_decode(file_get_contents($bannedIPsFile), true);

    // Entferne abgelaufene Sperren
    $currentTime = time();
    foreach ($bannedIPs as $bannedIP => $expiry) {
        if ($expiry < $currentTime) {
            unset($bannedIPs[$bannedIP]);
        }
    }

    // Aktualisierte Liste speichern
    file_put_contents($bannedIPsFile, json_encode($bannedIPs));

    return isset($bannedIPs[$ip]);
}

// Hauptlogik
$visitorIP = getVisitorIP();
$requestURI = $_SERVER['REQUEST_URI'] ?? '/';

if (isIPBanned($visitorIP)) {
    // Sperrmeldung anzeigen und Zugriff blockieren
    http_response_code(403);
    die('Zugriff verweigert. Ihre IP-Adresse wurde gesperrt.');
}

// Überprüfe, ob die URI verbotene Muster enthält
foreach ($forbiddenPatterns as $pattern) {
    if (preg_match($pattern, $requestURI)) {
        // IP-Adresse sperren
        banIP($visitorIP, $banDuration);

        // Sperrmeldung anzeigen
        http_response_code(403);
        die('Verbotenes Muster erkannt. Ihre IP-Adresse wurde gesperrt.');
    }
}
?>

In der Datei index.php im root Verzeichnis der WBCE-Installation gleich am Anfang der Code nach <?php folgende Zeile einfügen:

[== PHP ==]
include 'security_check.php'; // Schutz für alle Seiten

Die verbotene Zeichenkombinationen sowie die Sperrzeit werden gleich am Anfang der Datei security_check.php definiert:

        // Einstellungen
        $forbiddenPatterns = ['/test123/', '/hack/', '/badword/']; // Verbotene Muster (Regex)
        $banDuration = 60; // Sperrdauer in Sekunden (z. B. 1 Stunde)

Die Meldung, die bei der Sperrung angezeigt wird, kann am Ende der selben Datei definiert werden:

        // Sperrmeldung anzeigen
        http_response_code(403);
        die('Verbotenes Muster erkannt. Ihre IP-Adresse wurde gesperrt.');

Um die vorgeschlagene Lösung zu testen:

        Besuche die Webseite mit erlaubten URLs, um sicherzustellen, dass der Zugriff funktioniert.
        Greife mit einer verbotenen Zeichenkombination in der URL zu (z. B. /index.php?test123), um zu prüfen, ob die Sperrung funktioniert.
        Warte die Sperrdauer ab und prüfe, ob die IP-Adresse nach Ablauf wieder Zugriff hat.

Vielleicht kann man daraus ein WBCE-Modul basteln...

Offline

#5 03.12.2024 12:33:58

kleo
Member

Re: Access deny

Ich habe es mir überlegt, die Vorgehensweise etwas zu erweitern.

Die "fleißigen" unerwünschten Besucher rufen oft in sekundenschnelle mehrere UPI´s. Ein „normaler“ Mensch kann so was nicht.

Man kann versuchen durch die „Häufigkeitsbegrenzung“ auch solche Besucher sperren.

Um die oben vorgeschlagene Lösung zu ergänzen erstelle ich noch eine Datei Namens rate_limit.json im root Verzeichnis

Alle Einstellungen (auch die Fehlermeldungtexte) habe ich zur besseren Übersicht oben bei den Einstellungen gruppiert.

Hier ist die dafür der angepasste Code der Datei security_check.php:


[== PHP ==]
<?php
// Einstellungen
$forbiddenPatterns = ['/test123/', '/hack/', '/badword/']; // Verbotene Muster (Regex)
$banDuration = 30; // Sperrdauer in Sekunden (z. B. 60 = 1 Minute, 3600 = 1 Stunde)
$rateLimit = 3; // Maximale Anfragen pro Zeitfenster
$rateLimitWindow = 3; // Zeitfenster in Sekunden (z. B. 60 = 1 Minute, 3600 = 1 Stunde)

// Fehlermeldungen
$errorMessages = [
    'banned' => 'Zugriff verweigert. Ihre IP-Adresse wurde gesperrt.',
    'rate_limit' => 'Zu viele Anfragen. Bitte versuchen Sie es später erneut.',
    'forbidden_pattern' => 'Verbotenes Muster erkannt. Ihre IP-Adresse wurde gesperrt.'
];

// Dateien zur Speicherung von Sperren und Limits
$bannedIPsFile = 'banned_ips.json'; // Datei zur Speicherung der gesperrten IPs
$rateLimitFile = 'rate_limit.json'; // Datei zur Speicherung der Anfrage-Zähler

// Funktion, um die IP-Adresse des Besuchers zu ermitteln
function getVisitorIP() {
    return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
}

// Funktion, um eine IP-Adresse zu sperren
function banIP($ip, $duration) {
    global $bannedIPsFile;

    $bannedIPs = [];
    if (file_exists($bannedIPsFile)) {
        $bannedIPs = json_decode(file_get_contents($bannedIPsFile), true);
    }

    $bannedIPs[$ip] = time() + $duration;
    file_put_contents($bannedIPsFile, json_encode($bannedIPs));
}

// Funktion, um zu prüfen, ob eine IP gesperrt ist
function isIPBanned($ip) {
    global $bannedIPsFile;

    if (!file_exists($bannedIPsFile)) {
        return false;
    }

    $bannedIPs = json_decode(file_get_contents($bannedIPsFile), true);
    $currentTime = time();

    // Entferne abgelaufene Sperren
    foreach ($bannedIPs as $bannedIP => $expiry) {
        if ($expiry < $currentTime) {
            unset($bannedIPs[$bannedIP]);
        }
    }

    file_put_contents($bannedIPsFile, json_encode($bannedIPs));
    return isset($bannedIPs[$ip]);
}

// Funktion, um die Häufigkeitsbegrenzung zu überprüfen
function checkRateLimit($ip) {
    global $rateLimit, $rateLimitWindow, $rateLimitFile;

    $rateData = [];
    if (file_exists($rateLimitFile)) {
        $rateData = json_decode(file_get_contents($rateLimitFile), true);
    }

    $currentTime = time();

    // Entferne veraltete Einträge
    foreach ($rateData as $ipAddress => $data) {
        if ($data['timestamp'] + $rateLimitWindow < $currentTime) {
            unset($rateData[$ipAddress]);
        }
    }

    // Aktualisiere die Daten für die aktuelle IP
    if (!isset($rateData[$ip])) {
        $rateData[$ip] = ['count' => 1, 'timestamp' => $currentTime];
    } else {
        $rateData[$ip]['count'] += 1;
    }

    // Sperre die IP, wenn das Limit überschritten wurde
    if ($rateData[$ip]['count'] > $rateLimit) {
        file_put_contents($rateLimitFile, json_encode($rateData)); // Daten speichern
        return false; // Limit überschritten
    }

    file_put_contents($rateLimitFile, json_encode($rateData)); // Daten speichern
    return true;
}

// Hauptlogik
$visitorIP = getVisitorIP();
$requestURI = $_SERVER['REQUEST_URI'] ?? '/';

// Prüfen, ob die IP bereits gesperrt ist
if (isIPBanned($visitorIP)) {
    http_response_code(403);
    die($errorMessages['banned']);
}

// Häufigkeitsbegrenzung überprüfen
if (!checkRateLimit($visitorIP)) {
    http_response_code(429); // 429 Too Many Requests
    die($errorMessages['rate_limit']);
}

// Überprüfen auf verbotene Muster in der URI
foreach ($forbiddenPatterns as $pattern) {
    if (preg_match($pattern, $requestURI)) {
        // IP-Adresse sperren
        banIP($visitorIP, $banDuration);

        http_response_code(403);
        die($errorMessages['forbidden_pattern']);
    }
}

?>

Last edited by kleo (05.12.2024 13:42:01)

Offline

#6 03.12.2024 12:53:10

kleo
Member

Re: Access deny

Und noch eine Erweiterung.

Wenn der gesperrte Besucher innerhalb der Sperrzeit erneut die Webseite aufruft, wird die Sperrzeit neu gesetzt:

[== PHP ==]
<?php
// Einstellungen
$forbiddenPatterns = ['/adminer/', '/test123/', '/badword/']; // Verbotene Muster (Regex)
$banDuration = 10; // Sperrdauer in Sekunden (z. B. 60 = 1 Minute, 3600 = 1 Stunde)
$rateLimit = 3; // Maximale Anfragen pro Zeitfenster
$rateLimitWindow = 3; // Zeitfenster in Sekunden (z. B. 60 = 1 Minute, 3600 = 1 Stunde)

// Fehlermeldungen
$errorMessages = [
    'banned' => 'Zugriff verweigert.',
    'rate_limit' => 'Zu viele Anfragen. Bitte versuchen Sie es später erneut.',
    'forbidden_pattern' => 'Zugriff verweigert.'
];

// Dateien zur Speicherung von Sperren und Limits
$bannedIPsFile = 'banned_ips.json'; // Datei zur Speicherung der gesperrten IPs
$rateLimitFile = 'rate_limit.json'; // Datei zur Speicherung der Anfrage-Zähler

// Funktion, um die IP-Adresse des Besuchers zu ermitteln
function getVisitorIP() {
    return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
}

// Funktion, um eine IP-Adresse zu sperren
function banIP($ip, $duration) {
    global $bannedIPsFile;

    $bannedIPs = [];
    if (file_exists($bannedIPsFile)) {
        $bannedIPs = json_decode(file_get_contents($bannedIPsFile), true);
    }

    // Setze die neue Sperrzeit
    $bannedIPs[$ip] = time() + $duration;
    file_put_contents($bannedIPsFile, json_encode($bannedIPs));
}

// Funktion, um zu prüfen, ob eine IP gesperrt ist und ggf. die Sperrzeit zu verlängern
function isIPBanned($ip) {
    global $bannedIPsFile, $banDuration;

    if (!file_exists($bannedIPsFile)) {
        return false;
    }

    $bannedIPs = json_decode(file_get_contents($bannedIPsFile), true);
    $currentTime = time();

    // Entferne abgelaufene Sperren
    foreach ($bannedIPs as $bannedIP => $expiry) {
        if ($expiry < $currentTime) {
            unset($bannedIPs[$bannedIP]);
        }
    }

    file_put_contents($bannedIPsFile, json_encode($bannedIPs));

    // Falls die IP gesperrt ist, verlängere die Sperrzeit
    if (isset($bannedIPs[$ip])) {
        banIP($ip, $banDuration); // Sperrzeit zurücksetzen
        return true;
    }

    return false;
}

// Funktion, um die Häufigkeitsbegrenzung zu überprüfen
function checkRateLimit($ip) {
    global $rateLimit, $rateLimitWindow, $rateLimitFile;

    $rateData = [];
    if (file_exists($rateLimitFile)) {
        $rateData = json_decode(file_get_contents($rateLimitFile), true);
    }

    $currentTime = time();

    // Entferne veraltete Einträge
    foreach ($rateData as $ipAddress => $data) {
        if ($data['timestamp'] + $rateLimitWindow < $currentTime) {
            unset($rateData[$ipAddress]);
        }
    }

    // Aktualisiere die Daten für die aktuelle IP
    if (!isset($rateData[$ip])) {
        $rateData[$ip] = ['count' => 1, 'timestamp' => $currentTime];
    } else {
        $rateData[$ip]['count'] += 1;
    }

    // Sperre die IP, wenn das Limit überschritten wurde
    if ($rateData[$ip]['count'] > $rateLimit) {
        file_put_contents($rateLimitFile, json_encode($rateData)); // Daten speichern
        return false; // Limit überschritten
    }

    file_put_contents($rateLimitFile, json_encode($rateData)); // Daten speichern
    return true;
}

// Hauptlogik
$visitorIP = getVisitorIP();
$requestURI = $_SERVER['REQUEST_URI'] ?? '/';

// Prüfen, ob die IP bereits gesperrt ist
if (isIPBanned($visitorIP)) {
    http_response_code(403);
    die($errorMessages['banned']);
}

// Häufigkeitsbegrenzung überprüfen
if (!checkRateLimit($visitorIP)) {
    http_response_code(429); // 429 Too Many Requests
    die($errorMessages['rate_limit']);
}

// Überprüfen auf verbotene Muster in der URI
foreach ($forbiddenPatterns as $pattern) {
    if (preg_match($pattern, $requestURI)) {
        // IP-Adresse sperren
        banIP($visitorIP, $banDuration);

        http_response_code(403);
        die($errorMessages['forbidden_pattern']);
    }
}

?>

Offline

#7 04.12.2024 11:46:10

berny
Member

Re: Access deny

Verbotenes Muster erkannt. Ihre IP-Adresse wurde gesperrt

Ich würde das "Verbotene Muster" einfach weglassen.

Offline

#8 04.12.2024 12:49:42

kleo
Member

Re: Access deny

Die Fehlermeldungen kann man frei definieren. Und wenn man will, auch in verschiedenen Sprachen.
Man kann auch ein Bild an der Stelle von Textmeldungen zeigen.

Es ist zu überlegen, ob durch die "Häufigkeitsbegrenzung" nicht die Suchmaschinen bei Ihrer Arbeit gehindert werden.
Ich habe keine Ahnung, wie schnell die Suchmaschinen-Crawler einzelne Aufrufe tätigen.
Vielleicht kann man da durch eine bestimmte Einstellung für maximale Anzahl der Anfragen pro Zeitfenster regeln.

Eine andere Überlegung:
die beiden Dateien banned_ips.json und rate_limit.json mittels .htaccess von fremden Ansehen zu schützen.

Am besten wäre vielleicht ein Modul daraus zu erstellen.
Ich glaube aber nicht, dass ich es alleine schaffe...

Offline

#9 04.12.2024 13:47:50

webbird
Administrator

Re: Access deny

Seriöse Suchmaschinen kann man erkennen und ausnehmen.


Ich habe eine Amazon-Wishlist. wink Oder spende an das Projekt.
Ich kann, wenn ich will, aber wer will, dass ich muss, kann mich mal

Online

#10 05.12.2024 13:29:56

kleo
Member

Re: Access deny

Hi Webbird,

danke für den Tipp.

Ich habe weiter gebastellt und der Code mit der Suchmaschinen Erkennung ergänzt.

Hier ist es zum Testen:

[== PHP ==]
<?php
// Einstellungen
$forbiddenPatterns = ['/adminer/', '/test123/', '/badword/']; // Verbotene Muster (Regex)
$banDuration = 10; // Sperrdauer in Sekunden (z. B. 60 = 1 Minute, 3600 = 1 Stunde)
$rateLimit = 3; // Maximale Anfragen pro Zeitfenster
$rateLimitWindow = 1; // Zeitfenster in Sekunden (z. B. 60 = 1 Minute, 3600 = 1 Stunde)

// Fehlermeldungen
$errorMessages = [
    'banned' => 'Zugriff verweigert.',
    'rate_limit' => 'Zu viele Anfragen. Bitte versuchen Sie es später erneut.',
    'forbidden_pattern' => 'Zugriff verweigert.'
];

// Suchmaschinen-Roboter-User-Agents
$searchEngineBots = [
    'Googlebot',
    'Bingbot',
    'Slurp', // Yahoo
    'DuckDuckBot',
    'Baiduspider',
    'YandexBot',
    'Sogou',
    'Exabot',
    'facebot',
    'ia_archiver' // Alexa Crawler
];

// Dateien zur Speicherung von Sperren und Limits
$bannedIPsFile = 'banned_ips.json'; // Datei zur Speicherung der gesperrten IPs
$rateLimitFile = 'rate_limit.json'; // Datei zur Speicherung der Anfrage-Zähler

// Funktion, um die IP-Adresse des Besuchers zu ermitteln
function getVisitorIP() {
    return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
}

// Funktion, um zu prüfen, ob der aktuelle User-Agent ein Suchmaschinen-Bot ist
function isSearchEngineBot($userAgent, $bots) {
    foreach ($bots as $bot) {
        if (stripos($userAgent, $bot) !== false) {
            return true;
        }
    }
    return false;
}

// Funktion, um eine IP-Adresse zu sperren
function banIP($ip, $duration) {
    global $bannedIPsFile;

    $bannedIPs = [];
    if (file_exists($bannedIPsFile)) {
        $bannedIPs = json_decode(file_get_contents($bannedIPsFile), true);
    }

    // Setze die neue Sperrzeit
    $bannedIPs[$ip] = time() + $duration;
    file_put_contents($bannedIPsFile, json_encode($bannedIPs));
}

// Funktion, um zu prüfen, ob eine IP gesperrt ist und ggf. die Sperrzeit zu verlängern
function isIPBanned($ip) {
    global $bannedIPsFile, $banDuration;

    if (!file_exists($bannedIPsFile)) {
        return false;
    }

    $bannedIPs = json_decode(file_get_contents($bannedIPsFile), true);
    $currentTime = time();

    // Entferne abgelaufene Sperren
    foreach ($bannedIPs as $bannedIP => $expiry) {
        if ($expiry < $currentTime) {
            unset($bannedIPs[$bannedIP]);
        }
    }

    file_put_contents($bannedIPsFile, json_encode($bannedIPs));

    // Falls die IP gesperrt ist, verlängere die Sperrzeit
    if (isset($bannedIPs[$ip])) {
        banIP($ip, $banDuration); // Sperrzeit zurücksetzen
        return true;
    }

    return false;
}

// Funktion, um die Häufigkeitsbegrenzung zu überprüfen
function checkRateLimit($ip) {
    global $rateLimit, $rateLimitWindow, $rateLimitFile;

    $rateData = [];
    if (file_exists($rateLimitFile)) {
        $rateData = json_decode(file_get_contents($rateLimitFile), true);
    }

    $currentTime = time();

    // Entferne veraltete Einträge
    foreach ($rateData as $ipAddress => $data) {
        if ($data['timestamp'] + $rateLimitWindow < $currentTime) {
            unset($rateData[$ipAddress]);
        }
    }

    // Aktualisiere die Daten für die aktuelle IP
    if (!isset($rateData[$ip])) {
        $rateData[$ip] = ['count' => 1, 'timestamp' => $currentTime];
    } else {
        $rateData[$ip]['count'] += 1;
    }

    // Sperre die IP, wenn das Limit überschritten wurde
    if ($rateData[$ip]['count'] > $rateLimit) {
        file_put_contents($rateLimitFile, json_encode($rateData)); // Daten speichern
        return false; // Limit überschritten
    }

    file_put_contents($rateLimitFile, json_encode($rateData)); // Daten speichern
    return true;
}

// Hauptlogik
$visitorIP = getVisitorIP();
$requestURI = $_SERVER['REQUEST_URI'] ?? '/';
$userAgent = $_SERVER['HTTP_USER_AGENT'] ?? '';

// Prüfen, ob der Besucher ein Suchmaschinen-Bot ist
if (isSearchEngineBot($userAgent, $searchEngineBots)) {
    echo "Suchmaschinen-Bot erkannt. Keine Begrenzung angewendet.";
    exit;
}

// Prüfen, ob die IP bereits gesperrt ist
if (isIPBanned($visitorIP)) {
    http_response_code(403);
    die($errorMessages['banned']);
}

// Häufigkeitsbegrenzung überprüfen
if (!checkRateLimit($visitorIP)) {
    http_response_code(429); // 429 Too Many Requests
    die($errorMessages['rate_limit']);
}

// Überprüfen auf verbotene Muster in der URI
foreach ($forbiddenPatterns as $pattern) {
    if (preg_match($pattern, $requestURI)) {
        // IP-Adresse sperren
        banIP($visitorIP, $banDuration);

        http_response_code(403);
        die($errorMessages['forbidden_pattern']);
    }
}

?>

Ich habe hier zum Testen die Sperrdauer auf 10 Sekunden eingestellt, normal würde ich sie wahrscheinlich mindestens auf 1 Stunde setzen.

Last edited by kleo (05.12.2024 13:41:10)

Offline

Board footer

up