Ugrás a tartalomra
Rapcsány Krisztián Rapcsány Krisztián
← Összes cikk
2 perc olvasás

Botvédelem kapcsolati űrlapra captcha nélkül

Laravel Biztonság Űrlap

A saját oldalam kapcsolati űrlapját nem akartam captchával terhelni. Aki ajánlatot kér, ne kényszerüljön közlekedési lámpákat keresni a képeken. Ezért több, egymásra épülő láthatatlan réteget építettem, és külső szolgáltatást (Turnstile) csak akkor kapcsolok be, ha ezek kevésnek bizonyulnak.

Az öt réteg

  • Csapdamező. Egy rejtett mezőt a botok kitöltenek, az emberek nem is látják.
  • Időbélyeg. Az űrlap titkosított időbélyeget kap. Ha négy másodpercnél gyorsabban jön vissza, nem ember töltötte ki.
  • Emberi jel. Egy mezőt a JavaScript tölt ki az első kattintás vagy billentyű után. Ha hiányzik, nem tiltok ki senkit, csak hosszabb időt várok el.
  • Tartalom. Három hivatkozásnál több a levélben szinte mindig spam.
  • Kliens. Az üres vagy robotos böngészőazonosítót nem engedem át.
BotCheck.php
public static function reason(Request $request): ?string
{
    if ($request->filled('website')) {                 // honeypot: a hidden field only bots fill in
        return 'honeypot';
    }

    $ua = strtolower((string) $request->userAgent());
    if ($ua === '' || preg_match('/bot|crawl|spider|curl|wget|python|headless/', $ua)) {
        return 'ua';
    }

    try {
        $issued = (int) Crypt::decryptString((string) $request->input('_ts'));
    } catch (\Throwable) {
        return 'token';
    }

    $elapsed = time() - $issued;
    if ($elapsed < 4) {                                // faster than a person can type
        return 'too-fast';
    }

    // Set by JavaScript on the first real interaction. Without it, expect a slower visitor.
    $humanSignal = preg_match('/^h[a-z0-9]{3,20}$/', (string) $request->input('_js')) === 1;
    if (! $humanSignal && $elapsed < 20) {
        return 'no-js';
    }

    if (preg_match_all('~https?://|www\.~i', (string) $request->input('message')) > 2) {
        return 'links';
    }

    return null;
}

Kivonat valódi kódból, anonimizálva.

A bot ne tudja, hogy elbukott

Ha egy ellenőrzés elbukik, ugyanazt a sikeres képernyőt mutatom, mintha minden rendben lenne. A bot így semmilyen visszajelzést nem kap, amiből tanulhatna. Én közben a (személyes adat nélküli) naplóból látom, melyik réteg fogott meg valamit.

A valódi látogatóra is figyelni kell

A legfontosabb szabály az, hogy a védelem ne akadályozza a valódit. A JavaScript nélküli látogató sem marad ki, csak hosszabb időt várok el tőle, húsz másodpercet. Az űrlap egy napig érvényes, és ha lejár, a látogató kérést kap az újratöltésre, nem néma hibát.

Hasonló problémán dolgozol?

Ha elakadtál, vagy átnéztetnéd a megoldásodat, írj, szívesen megnézem.

Írok neked →
Ajánlatot kérek →