Elucubrato da saibal
Addì 22 Marzo 2013
Rivisitazione della tecnica “honeypot” per moduli antispam senza captcha – UPDATE
La pagina di invio
Rispetto all’esempio precedente, la pagina di invio prevede delle verifiche aggiuntive. Anche in questo caso il codice è stato scritto separando ogni controllo per illustrare meglio i passi eseguiti; ogni volta verrà inviata una email a scopo di debug.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | <?php /* * Filename: result1.php */ $salt = 'parola-segreta'; $minsec = 1; $now = time(); // il metodo di invio è post if ($_SERVER['REQUEST_METHOD'] == 'POST') { // esiste il campo con il carattere random e non è vuoto if (!empty($_POST['rchar'])) { // esiste il campo con la data e non è vuoto if (!empty($_POST['formtime'])) { // il campo con la data è numerico if (is_numeric($_POST['formtime'])) { // la data di invio è futura rispetto a quella del form if ($now > $_POST['formtime']) { // il tempo trascorso tra il caricamento e l'invio è maggiore di n secondi if (($now - $_POST['formtime']) > $minsec) { // esiste il cookie if (isset($_COOKIE['hashcode'])) { // se il contenuto del cookie è uguale alla chiave generata con il salt if ($_COOKIE['hashcode'] == md5($salt.$_POST['formtime'].$_POST['rchar'])) { // ho i dati per comporre il nome del campo honeypot $honeypot = $_POST['rchar'].$_COOKIE['hashcode']; // il campo fake esiste ed è vuoto if (isset($_POST[$honeypot]) && empty($_POST[$honeypot])) { $result = "messaggio scritto da umani"; } else { $result = "bot: riempito campo fake o mancante"; } } else { echo "codice cookie: " .$_COOKIE['hashcode']; echo "<br />"; echo "codice generato: " .md5($salt.$_POST['formtime'].$rchar); echo "<br /><br />"; $result = "bot: il contenuto del cookie non corrisponde al codice generato"; } } else { $result = "bot: non esiste il cookie"; } } else { $result = "bot: troppo veloce - tempo di invio: " .($now - $_POST['formtime']). " secondi"; } } else { $result = "bot: troppo veloce - tempo di invio: futuro"; } } else { $result = "bot: time manomesso"; } } else { $result = "bot: manca timestamp"; } } else { $result = "bot: manca il campo rchar"; } } else { $result = "bot: la request è diversa da POST"; } /**************** INVIO EMAIL ******************/ $dest = "miaemail@provider.com"; $headers = "X-Mailer: PHP ".phpversion()."\n"; $headers .= "From: $_POST[email] <$_POST[email]>\n"; $headers .= "Return-Path: $dest <$dest>\n"; $headers .= "Reply-To: $dest <$dest>\n"; $headers .= "Date: ".date("H:i:s")." ".date("d/m/Y")."\n"; $headers .= "Delivered-to: $dest <$dest>\n"; $headers .= "MIME-Version: 1.0\n"; $corpo = "ora invio: " .$now. "\n ora form: " .$_POST['formtime']. "\r\n" .stripslashes($_POST["message"]); if (isset($honeypot) && !empty($_POST[$honeypot])) { $corpo .= "\r\n honeypot:" .stripslashes($_POST[$honeypot]); } //invio dell'email mail($dest,$result,$corpo,$headers); setcookie('hashcode','', -1000, '/'); echo $result; ?> |
Come valore di “$salt” ricordiamoci di inserire la stessa parola chiave usata nella creazione del form. La variabile “$minsec” indica i secondi che devono passare tra la visualizzazione del form e l’invio.
In questo secondo esempio i controlli sono maggiori rispetto a prima ma sempre molto chiari. Sostanzialmente si verifica che:
- il metodo di invio sia POST
- il campo “rchar” esista e non sia vuoto. ciò presuppone javascript attivo
- il campo “formtime” esista e non sia vuoto
- il campo “formtime” sia numerico
- il campo “formtime” sia inferiore alla data di invio
- il tempo trascorso tra la visualizzazione del form e l’invio non deve essere inferiore a “$minsec”
- il cookie di controllo esista
- il valore del cookie di controllo sia uguale al codice md5 dei seguenti campi concatenati: $salt, $_POST[‘formtime’] e $_POST[‘rchar’]
- il campo honeypot deve esitere ma essere vuoto
Il nome del campo invisibile, essendo random, non è deducibile a priori. Si ottiene semplicemente unendo i dati in nostro possesso:
1 | $honeypot = $_POST['rchar'].$_COOKIE['hashcode']; |
Superati questi controlli allora si può procedere con l’invio del modulo e con la cancellazione del cookie che dovrebbe evitare l’utilizzo del tasto indietro per effettuare un nuovo submit.
Questo secondo esempio, con qualche controllo in più, è decisamente più efficiente del primo. La chiave di volta, secondo me, è l’utilizzo del campo “rchar” stampato via jQuery e l’utilizzo del cookie che permette di rendere randomici molti elementi.
Dai test effettuati il risultato è ottimo. Probabilmente sono stati effettuati attacchi con bot “stupidi” ma la maggior parte di loro sono stati fermati dalla mancanza del campo “rchar”. Ciò significa che non avevano javascript attivo.

Vota: %SAIBAL_PERCENTAGE%%
bell’articolo! complimenti!!!
l’ho provato e funziona bene come tecnica