presseportale/app/Services/Spam/GibberishDetector.php
Kevin Adametz 06d2889a4d feat: Spamschutz für Kontakt-Widget und Registrierung mit Cloudflare Turnstile
- Turnstile für Gäste und unbestätigte Konten (TurnstileVerifier,
  <x-turnstile>); ist Cloudflare nicht erreichbar, wird durchgelassen und
  im Verlauf, in der Kontakt-Queue und in der Betriebsüberwachung markiert
- Inhaltsfilter des Kontaktformulars (fremde Links, Floskel mit
  Seitentitel, Zeichensalat, Sperrliste, Absenden unter 3 Sekunden);
  Treffer landen in der Spam-Quarantäne ohne Mail, Löschung nach 30 Tagen
- Admin: Filter „Spam“, Sammelaktion, „Kein Spam“ holt die Mail nach
- Registrierung lehnt Zufallsnamen ab; users:prune-bot-registrations
  (täglicher Lauf erst mit USERS_PRUNE_BOT_REGISTRATIONS=true)
- contact-messages:quarantine-spam für den Altbestand
- CSP erlaubt challenges.cloudflare.com, Log-Kanal spam
- Datenschutzerklärung: Abschnitt 6a Cloudflare Turnstile (Vorschlag)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 08:49:58 +00:00

44 lines
1.5 KiB
PHP

<?php
namespace App\Services\Spam;
/**
* Erkennt Zufallszeichenketten, wie sie Bots in Namensfelder schreiben
* („ruLrlotwaCoVStmZetSxD“, „NAEWTRER2720160NEYRTHYT“).
*
* Beide Regeln sind am Bestand vom 07.10.2026 gemessen: keine einzige
* Person unter rund 67.000 Konten und 0 Kontakte getroffen.
*/
final class GibberishDetector
{
/**
* Personenname (Registrierung): ein einziges Wort aus mindestens 12
* Buchstaben mit mindestens drei Großbuchstaben nach dem ersten Zeichen.
* Trifft im Bestand 511 Bot-Konten und keinen echten Namen. Firmennamen
* wie „StammZellenPowerTeam“ fielen darunter — darum nur für Personen.
*/
public static function isRandomPersonName(string $name): bool
{
$name = trim($name);
return preg_match('/^[A-Za-z]{12,}$/', $name) === 1
&& preg_match_all('/[A-Z]/', substr($name, 1)) >= 3
&& preg_match_all('/[a-z]/', $name) >= 3;
}
/**
* Freies Namensfeld, das auch Firmen tragen kann (Kontaktformular):
* mindestens vier Wechsel von klein auf groß („…aCoVStmZet…“), oder ein
* Block Großbuchstaben + Ziffern + Großbuchstaben.
*/
public static function isRandomToken(string $value): bool
{
$value = trim($value);
if (preg_match('/^[A-Za-z]{12,}$/', $value) === 1 && preg_match_all('/[a-z][A-Z]/', $value) >= 4) {
return true;
}
return preg_match('/[A-Z]{5,}\d{4,}[A-Z]{5,}/', $value) === 1;
}
}