Captchas sind heutzutage kaum noch wegzudenken, fast jede Seite benötigt mindestens bei der Registration die Eingabe eines Captchas, um automatisch ausgeführte Anmeldungen zu verhindern. Ziel ist es, jeglichen Spam sowie automatisierte Operationen abzuhalten oder mindestens zu minimieren. Daher trifft man häufig bei Kommmentarsystemen auf solche Captcha-Implementierungen.
Als ich wieder ziellos durch das Internet zog, hat es mir eine Seite besonders angetan: Das eingesetzte System wurde selbst programmiert und beruht auf PHP und MySQL.
Ersteindruck: Mangelhaft?
Dem interessierten Leser wird ein Bild mit vier Zeichen präsentiert. Wie üblich soll diese Zeichenkette abgetippt werden, um Spam abzuhalten. Allerdings fielen hier bereits negative Punkte auf: Die
- Buchstaben bestanden aus astreiner Arial-Blockschrift in Großbuchstaben.
- Zahlen waren keine vorhanden.
Das macht es natürlich noch einfacher, über OCR die passenden Zeichen auszulesen.
Doch damit nicht genug. Hier wurde absolut gar nichts generiert. Die Buchstabenketten wiederholen sich. Es existieren im Ordner 10 verschiedene Bilder mit 10 unterschiedlichen Buchstabenketten, welche zufällig dann eingebunden werden.
Zweiteindruck: Bestätigt!
Als Alternative zum Auslesen des Bildes, wird ein POST-Request eine Weile in einer Schleife durchlaufen.Bei 10 Prozent der Anfragen müsste logischerweise das richtige Captcha angenommen werden. Nach 200 Requests sollten also mindestens 20 der Kommentare durchkommen.
Doch während dieses Tests fiel mir noch etwas weiteres auf:
Über einen manuellen POST-Request wurde der Kommentar jederzeit angenommen – egal ob man immer das gleiche Captcha verwendete oder ein neues.
Sehr ungünstig für eine Webanwendung, doch woran lag dies?
Codespekulationen
Da ich leider keinen Zugriff auf den Quellcode besitze, kann ich nur ein wenig spekulieren, was hier falsch gemacht wurde.
Fest steht: Es wurden einfach zufällige Bilder per PHP eingebunden.
Dies lässt sich ja recht einfach implementieren.
<?php //Zufällige Zahl zwischen 1 und 10 $zufall=mt_rand(1,10); //Bildausgabe echo '<img src="captcha/images/'. $zufall .'.png" title="captcha" />'; ?>
Nun könnte man mutmaßen, dass die Lösung „hardcoded“ im Script selbst verborgen ist und dort einfach nur der übergebene Wert verglichen wird.
Dementsprechend weiß das Script selber nicht, welches Captcha gerade abgefragt wird.
$captchas = array("AHFJ", "WJVK", "VKSW", "WPSX", "NCMS", "LSDD", "XCDK", "ZULU", "POJQ", "RYKL"); if(in_array($_POST['code'], $captchas)) { /* weiterer Code */ }
Aber falsch:
Stattdessen wurde auf eine ganz andere Methode gesetzt. Ein weiterer Blick in die mitgeschnittenen POST-Requests verrät, wo der Hase hängt. Der User selbst überträgt über $_POST sowohl das eingetippte Captcha, als auch die passende Lösung.
Sollten beide Werte vom Script erfolgreich verglichen worden sein, so wird der Kommentar angenommen.
Heißt: Wir brauchen nichts auslesen.
if(strcmp($_POST['code'], $_POST['valid_code'])==0) { /* weiterer Code */ }
Fazit:
Eine ordentliche Captcha-Abfrage lässt sich nicht in fünf Minuten entwickeln. Stattdessen braucht man Zeit, Geduld und ein Näschen für die richtige Mischung zwischen Funktionalität und Usability. Captchas sollen zwar für den Nutzer lösbar sein, aber auch hier gibt es einige Variationsmöglichkeiten. In diesem Beispiel waren nicht nur die Captchas selbst unzureichend, sondern auch direkt das Script, welches diese annehmen soll.
- Die Lösung eines Captchas sollte nicht im hidden-field im Quelltext der Seite stehen und dementsprechend über den POST Request mitgesendet werden. Ansonsten fällt es einem Bot besonders leicht, das richtige Captcha auszulesen.
Bleibt die Möglichkeit das ganze in einer Session zu speichern, einen Cookie zu setzen oder das ganze über eine Datenbank abzuwickeln.
- Ein Captcha selber ist zu einfach. Es ist quasi ein einfaches Bild mit vier normalen Buchstaben. Bots werden keine Probleme haben, diese auszulesen. Es empfielt sich ein ausgereifteres System (Googles reCaptcha, SecureImage).
Oder geht es vielleicht auch ganz ohne Captchas?.
Sollte es eine selbstverfasste Implementation werden, so muss diese gewisse Sicherheitsmerkmale besitzen (vgl. sitepoint.com).