Captcha Alternative: effektiver JavaScript SpamFilter

 

Ich wollte einen Besucherzähler für mein CMS schreiben und hab dabei relativ schnell bemerkt, dass der Großteil der Besucher keine wirklichen Besucher, sondern automatische Abfragen von Servern, sind. Das selbe Problem hatte ich seit jeher mit Formularen, diese wurden regelrecht zugespamt. 

Wie kann man effektiv einen Bot von einem richtigen Besucher unterscheiden?

Captcha

Eine sehr gängige Variante sind Captcha, kleine Bilder bei denen Benutzer Zahlen oder Buchstabenkombinationen beantworten müssen. Aufgrund der Komplexität der Bilder sind diese des öfteren nicht so leicht zu beantworten. Teilweise gibt es auch Varianten in denen eine Rechnung oder einfache Frage steht, Benutzer können diese meist leichter beantworten als ein Bot.

Das System funktioniert bei Formularen auf Kosten der Benutzerfreundlichkeit, nicht aber bei einem Besucherzähler. Wenn ich bei einem Besucherzähler echte Benutzer erkennen will, kann ich dem Leser kein Captcha zumuten um gezählt zu werden.

Aus Benutzersicht würde ich behaupten: Captcha nerven.

Was macht ein Browser, was ein Bot nicht kann?

Wie sieht das mit JavaScript aus: wieviel Javascript kann ein Bot?

Die Idee: Wenn Teile der Seite dynamisch mit Javascript generiert werden, beispielsweise der Aufruf des Besucherzählers, könnten die Bots doch außen vor gelassen werden, oder?

das wollte ich testen:

 

Der Versuchsaufbau

jQuery lädt mittels ajax (also erst nachdem die Seite geladen wurde) dynamisch den Besucherzähler nach:

Jeder moderne Browser kann das, und da Bots meist nur statischen Inhalt abrufen können, kommen wir mit diesem Ansatz schon sehr weit.

 

Folgendes jQuery Script soll den Besucherzähler aufrufen:

$( document ).ready(function() {
$.ajax({url:'counter.php'});
});

(hier nur in vereinfachter Form dargestellt: natürlich könnte counter.php direkt aufgerufen werden und den Besucher dann zählen, mit etwas zusätzlichem Code kann das leicht verhindert werden. Außerdem verlieren wir einige Informationen über den Benutzer, z.B. den HTTP-Referrer. Auch hier benötigen wir noch zusätzlichen Code. Um das Beispiel einfach zu halten, lasse ich diesen zusätzlichen Code jetzt mal absichtlich weg.)

 

Ein Bot müsste als jQuery interpretieren können um die Datei zu laden.

Ich hab den Code auf meinen Seiten getestet und konnte mit dieser Variante alle Bots richtig einordnen, mit Außname des Googlebot: dieser hat unser Skript dennoch interpretiert und taucht in dem generierten Logfile auf:

Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)

Mozilla/5.0 (compatible; Googlebot-Mobile/2.1; +http://www.google.com/bot.html)

Googlebot kann also ein wenig JavaScript und folgt dem AJAX-Aufruf welcher mittels $( document ).ready(function()  beim laden der Seite aufgerufen wird. Auch wenn Googlebot das Skript richtig ausführt, gibt es dennoch Aktionen, die einem wirklichen Benutzer vorbehalten sind:

kann ein Bot die Maus bewegen?

Ich würde mal behaupten, ein Bot hat gar keine Maus, diesen Nachteil können wir nützen.

Ein Benutzer streicht doch bestimmt kurz mit der Maus über den Bildschirm, wenn die Seite geladen wurde. Geräte ohne Maus haben ein Touchdisplay, welches beim Laden unweigerlich berührt wird.

Mit dem Evenhandler mousemove und touchmove liefert ein Besucherzähler wirklich gute Ergebnisse:

$( "body" ).one("mousemove touchmove",function()  {
$.ajax({url:'counter.php'});
});

auch Googlebot wird mit dieser Variante richtig erkannt. 

 

Für

Formulare

haben wir noch mehr Möglichkeiten, da der Benutzer das Formular ja ausfüllen muss, hier kann beispielsweise das Event focus() verwendet werden.

 

Die Idee:

Ein Event befüllt mittels jquery und einem Ajax Request ein verstecktes Formularfeld, der Server muss nach dem Post-Event überprüfen ob das Formularfeld den richtigen Wert enthält. Die Berechnung des Wertes muss natürlich beim Ajax Request und dem eigentlichen speichern des Formulares, das selbe Ergebnis liefern. Für die Berechnung kann beispielsweise ein Hash einer Kombination aus Uhrzeit und Clientinformationen, wie der IP Adresse oder ähnliches, gewählt werden.

Diese Variante macht Captcha oder ähnliche Ansätze völlig überflüssig.

 

Das Prinzip hab ich in dem Content Management System LiBe CMS umgesetzt und erfolgreich getestet, sowohl für den Besucherzähler, als auch für Formulare; siehe:Besucherzähler

positive Bewertung({{pro_count}})
Beitrag bewerten:
{{percentage}} % positiv
negative Bewertung({{con_count}})

DANKE für deine Bewertung!

Fragen / Kommentare


(sortiert nach Bewertung / Datum) [alle Kommentare(neueste zuerst)]

✍anonym
14.07.2020 14:53
Sehr cooler Ansatz. ABER:
„Ein Benutzer streicht doch bestimmt kurz mit der Maus über den Bildschirm, wenn die Seite geladen wurde. Geräte ohne Maus haben ein Touchdisplay, welches beim Laden unweigerlich berührt wird.“
Diese Annahme ist falsch. User mit Sehbehinderung oder auch User mit Körperbehinderungen, z.B. mit Tremor der Hände, nutzen weder Maus noch Touchscreen. Sie nutzen Tastaturen oder Eingabegeräte, die Tastatureingaben simulieren.
Möglicherweise gibt es noch andere Nutzergruppen, auf die die Annahme nicht zutrifft.

✍anonym
13.10.2015 12:27
User: Michael 
Mensch, da überlegt man die ganze Zeit und entschließt sich, die Frage zu posten, weil man nicht weiter kommt... und 2 Minuten später fällt einem die Lösung ein :-)

Für alle, die dasselbe Problem haben: Ich lese einfach den Titel der Seite in der Hauptseite aus uns speichere ihn in eine Variable. Diese übergebe ich dann an die analyse.php, indem ich diese folgendermaßen einbinde:

 $.ajax({url:'analyse.php?titel='});

In der Analyse.php lese ich den Wert mit GET aus und kann diesen dann in die Datenbank schreiben. So funktioniert es!

✍anonym
13.10.2015 12:17
User: Michael 
Moin, moin! Ich habe mir selbst ein Skript gebastelt, um mir live anschauen zu können, wieviele User gerade auf meinen Seiten sind. Und aufgrund der vielen Bots wichen die Zahlen von den Live-Stats von zB Google Analytics sehr weit ab. Dank Deines Beitrags kann ich nun realistischere Zahlen ausgeben. Denn ich laden die analyse.php-Datei einfach per Javascript nach.

Das Problem was ich nun habe: Ich kann jetzt nicht mehr auslesen, welche Seite der Besucher gerade anschaut. Entweder ist die Angabe leer oder aber es wird der Name der analyse.php ausgegeben; ich schaffe es aber nicht, den Namen der Datei ausgeben zu lassen, die vom User aufgerufen wird und innerhalb der dann die analyse.php nachgeladen wird. Gibt es hierfür eine Lösung?

Grüße!

✍anonym
07.07.2015 17:19
User: udo 
geniale Sache!