- PHP 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Ein Bouncer-Schluessel darf nur lesen. Der Reporter meldet mit den Zugangsdaten einer Machine eigene Beobachtungen als Alarm samt Entscheidung - ein Alarm ohne Entscheidung waere nur sichtbar, wuerde aber niemanden sperren. Das JWT wird zwischengespeichert; laeuft es ab, meldet sich der Reporter neu an und sendet erneut. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
| src | ||
| tests | ||
| .gitignore | ||
| composer.json | ||
| README.md | ||
CrowdSec Bouncer und Reporter (PHP)
Ein schlanker Bouncer für die lokale CrowdSec-API (LAPI) – ohne Composer, ohne Framework, ohne WordPress.
Wozu
CrowdSec sammelt auf dem Server Signale über auffällige IP-Adressen und legt
Entscheidungen ab (ban, captcha). Ein Bouncer fragt diese Entscheidungen
ab und setzt sie um. Diese Klasse ist genau dieser Frageteil – was danach
passiert, entscheidet die Anwendung.
Voraussetzung
Auf dem Server läuft CrowdSec, und die Anwendung erreicht dessen LAPI
(üblicherweise http://127.0.0.1:8080). Ein Bouncer-Schlüssel entsteht mit:
sudo cscli bouncers add mein-bouncer
Ohne laufende CrowdSec-Instanz bringt die Klasse nichts – sie gibt dann
immer none zurück.
Verwendung
HTTP und Zwischenspeicher werden hineingereicht, damit die Klasse in jeder Umgebung läuft. In WordPress etwa so:
use Valitype\CrowdSec\Bouncer;
require __DIR__ . '/vendor/crowdsec-bouncer/src/Bouncer.php';
$bouncer = new Bouncer(
'http://127.0.0.1:8080',
'BOUNCER_SCHLUESSEL',
array(
'http' => static function ( $url, $headers, $timeout ) {
$response = wp_remote_get( $url, array( 'headers' => $headers, 'timeout' => $timeout ) );
if ( is_wp_error( $response ) ) {
throw new Exception( $response->get_error_message() );
}
return array(
'code' => wp_remote_retrieve_response_code( $response ),
'body' => wp_remote_retrieve_body( $response ),
);
},
'cacheGet' => static function ( $key ) {
return get_transient( $key );
},
'cacheSet' => static function ( $key, $value, $ttl ) {
set_transient( $key, $value, $ttl );
},
)
);
if ( $bouncer->isBanned( $ip ) ) {
wp_die( 'Zugriff verweigert.', '', array( 'response' => 403 ) );
}
Einstellungen
| Schlüssel | Standard | Bedeutung |
|---|---|---|
http |
– | Callback ( $url, $headers, $timeout ): array{code,body}. Pflicht. |
cacheGet |
– | Callback ( $key ): mixed. Ohne ihn wird jede Anfrage durchgereicht. |
cacheSet |
– | Callback ( $key, $value, $ttl ): void. |
timeout |
2 |
Sekunden. Kurz halten – die LAPI ist lokal. |
cacheTtl |
60 |
Sekunden, die eine Entscheidung gilt. |
fallback |
none |
Was gilt, wenn die LAPI nicht antwortet. |
Grundsatz
Im Zweifel durchlassen. Eine nicht erreichbare LAPI, ein Zeitüberschreiten
oder eine unverständliche Antwort führen zu none, nicht zu einer Sperre.
Wer das anders will, setzt fallback auf ban – und sollte sich sicher sein.
Rückgaben
getDecision( $ip ) liefert ban, captcha oder none. Liegt zu einer IP
sowohl ban als auch captcha vor, gewinnt ban.
Verbindung prüfen
$result = $bouncer->testConnection();
// array( 'status' => 'ok'|'error', 'message' => '...' )
Vorfälle melden
Ein Bouncer-Schlüssel darf nur lesen. Wer eigene Beobachtungen an CrowdSec melden will, braucht Zugangsdaten einer Machine:
sudo cscli machines add mein-melder --password 'geheim'
Damit meldet Reporter einen Alarm samt Entscheidung:
use Valitype\CrowdSec\Reporter;
$reporter = new Reporter(
'http://127.0.0.1:8080',
'mein-melder',
'geheim',
array(
'http' => $post, // ( $url, $headers, $timeout, $body ): array{code,body}
'cacheGet' => 'get_transient',
'cacheSet' => $set,
'scenario' => 'meine-app/spam',
'duration' => '4h',
)
);
$reporter->report( $ip, array( 'message' => 'Formular-Spam' ) );
Der Alarm enthält die Entscheidung ausdrücklich mit. Ein Alarm ohne
Entscheidung taucht zwar in cscli alerts list auf, sperrt aber niemanden –
CrowdSec leitet daraus von sich aus nichts ab.
Das JWT aus POST /v1/watchers/login wird zwischengespeichert; läuft es ab,
meldet sich der Reporter automatisch neu an und sendet erneut.
Prüfen lässt sich die Anmeldung mit testConnection().
Lizenz
GPL-2.0-or-later