Elucubrato da saibal
Addì 22 marzo 2013
Rivisitazione della tecnica “honeypot” per moduli antispam senza captcha – UPDATE
Esempio n° 2
Codice da inserire in testa alla pagina:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
<?php /* * Filename: antispam-form2.php */ $salt = 'parola-segreta'; $rchar = chr(97 + mt_rand(0, 25)); $time = time(); $hash_real = md5($salt.$time.$rchar); $hash_fake = md5($salt.($time+rand(1,999)).$rchar); $code_real = $rchar.$hash_real; $code_fake = $rchar.$hash_fake; setcookie('hashcode',$hash_real, 0, '/'); ?>
Utilizziamo jQuery nell’head della pagina:
1 2 3 4 5 6 7 8 9 10 11
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script> <script type="text/javascript"> <!-- $(document).ready(function() { $('#<?php echo $code_real; ?>').attr("autocomplete","off"); $('.<?php echo $code_real; ?>').css('display','none'); $('#formtime').append('<input type="hidden" id="rchar" name="rchar" value="<?php echo $rchar; ?>" />'); }); //--> </script>
il form, invece, è così costruito:
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
<form id="<?php echo $code_fake; ?>" action="result2.php" method="post"> <input type="hidden" id="formtime" name="formtime" value="<?php echo $time; ?>" /> <fieldset> <legend>Guestbook Form:</legend> <div class="<?php echo $code_fake; ?>"> <label for="subject">Subject:</label> <input id="subject" name="subject" type="text" size="30" /> </div> <div class="<?php echo $code_fake; ?>"> <label for="email">Email:</label> <input id="email" name="email" type="text" size="30" /> </div> <div class="<?php echo $code_fake; ?>"> <label for="message">Message:</label> <textarea id="message" name="message" rows="10" cols="15"></textarea> </div> <div class="<?php echo $code_real; ?>"> <p>attenzione! lasciare vuoto questo campo</p> <input id="<?php echo $code_real; ?>" name="<?php echo $code_real; ?>" type="text" /> <p>attenzione! lasciare vuoto questo campo</p> </div> <input type="submit" value="Invia" /> </fieldset> </form>
Vediamo nel dettaglio come è stata strutturata la pagina.
Rispetto all’esempio precedente salta subito all’occhio che, una volta ottenuto un valore random con “time()”, lo codifichiamo con un salt (valore pseudo casuale) a cui aggiungiamo anche una singola lettera che analizzeremo tra poco. Sostanzialmente stiamo creando un controllo di sicurezza che sfrutta il confronto tra codici. Ciò dovrebbe rendere più difficile falsificare i moduli.
Il passo successivo è ottenere due codici simili (ma necessariamente diversi) per distinguere la classe del campo invisibile da tutte le altre.
A tal proposito aggiungiamo un numero random, compreso tra 1 e 999, ad una delle due variabili derivanti da “time()”. “$time_fake” verrà utilizzata per rendere univoco, ad ogni caricamento, l’id del form e le classi dei vari elementi (tranne il campo invisibile). “$time_real”, invece, ci servirà per l’honeypot e per ricostruire e confrontare i codici di controllo.
Nell’esempio n°1 abbiamo inserito i prefissi “form_” e “class_” dato che le specifiche vietano i numeri come primo carattere. Per risolvere anche questo problema (e rendere definitivamente random gli id, le classi e i nomi degli elementi) utilizzeremo una lettera casuale da usare come primo carattere con la funzione:
1
$rchar = chr(97 + mt_rand(0, 25));
In buona sostanza, con il codice visto, otterremo un form molto simile a questo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
<form id="o6c0f52f3fde3a444123541e2d5b12b37" action="result2.php" method="post"> <div class="o6c0f52f3fde3a444123541e2d5b12b37"> <label for="subject">Subject:</label> <input id="subject" name="subject" type="text" size="30" /> </div> <div class="o6c0f52f3fde3a444123541e2d5b12b37"> <label for="email">Email:</label> <input id="email" name="email" type="text" size="30" /> </div> <div class="o121b87f25b2a5b057bc00355bbe0f929"> <p>attenzione! lasciare vuoto questo campo</p> <input id="o121b87f25b2a5b057bc00355bbe0f929" name="o121b87f25b2a5b057bc00355bbe0f929" type="text" /> <p>attenzione! lasciare vuoto questo campo</p> </div> <input type="submit" value="Invia" /> </form>
L’obiettivo era rendere il modulo meno “schematico” possibile, in modo che fosse difficile basarsi su modelli fissi. Abbiamo cercato di rendere randomici più elementi possibili. Volendo potrebbe essere fatto ancora molto, magari creando id univoci anche per i campi “email” e “subject”.
Ovviamente tutto ciò che è random adesso va “memorizzato” per poterlo confrontare nella pagina di invio. Per questo motivo abbiamo introdotto l’utilizzo dei cookie. Al caricamento della pagina salviamo un cookie di sessione con $hash_real come contenuto. Questo dato non è comunque sufficiente per effettuare le verifiche. Abbiamo necessità anche di conoscere l’orario in cui è stato stampato il modulo, la lettera random usata e, ovviamente, la parola segreta.
Il primo degli elementi mancanti lo otteniamo dal campo hidden “formtime”. Anche la lettera casuale ci viene fornita da un elemento nascosto ma questa volta viene stampato attraverso jQuery.
Infine usiamo del codice javascript per nascondere il div “honeypot” che ha, rispetto al primo esempio, una classe random.
Questi due espedienti, seppur banali, implicano che il bot abbia javascript abilitato altrimenti l’elemento “rchar” non sarà presente nella pagina di invio e le operazioni si bloccheranno. A questo aggiungiamo che è necessario che il client sia in grado di accettare i cookie altrimenti si verificherà un errore.
Ecco spiegate in sintesi queste poche righe:
1 2 3
$('#<?php echo $code_real; ?>').attr("autocomplete","off"); $('.<?php echo $code_real; ?>').css('display','none'); $('#formtime').append('<input type="hidden" id="rchar" name="rchar" value="<?php echo $rchar; ?>" />');
Come prima è fondamentale l’attributo autocomplete su off.
bell’articolo! complimenti!!!
l’ho provato e funziona bene come tecnica