Fast jeder Seitenbetreiber, der ein Formular auf seiner Website anbietet, hat schon Erfahrungen mit automatisch abgesendeten Web-Formularen gemacht. Sie werden seit langem gern von Spammern genutzt, um Spam-Nachrichten zu verbreiten. CAPTCHAs helfen, Menschen von automatischen Spam-Schleudern zu unterscheiden. Allerdings haben sie zahlreiche Nachteile.
Je unleserlicher ein CAPTCHA ist desto sicherer ist es, weil es per Software mit vernünftigem Aufwand kaum noch auszulesen ist. Das ist keine wirklich elegante Lösung für das Spam-Problem, denn mit höherer Sicherheit sinkt auch die Lesbarkeit der CAPTCHAs. Das gilt ganz besonders für Menschen mit Sehbehinderungen. Für Web-Entwickler haben sie den Nachteil, dass eine Grafik-Bibliothek installiert sein muss, zum Beispiel die GD Library oder ImageMagick. Das wiederum erhöht die Komplexität einer Installation, weil die Bibliothek nachinstalliert oder die Skriptsprache mit entsprechender Unterstützung neu kompiliert werden muss. Das ist besonders für Webdesigner mit fehlenden technischen Kenntnissen eine große Hürde.
CAPTCHAs haben also viele Nachteile. Wer auf Barrierefreiheit setzt – eigentlich sollte das jeder – wird daher sicher auf CAPTCHAs verzichten. Dennoch gibt es Situationen, in denen man nicht um sie herumkommt. Andere Sicherungsmechanismen können außerdem noch wesentlich komplexer sein.
Ein pseudo-grafisches CAPTCHA merzt einige Nachteile aus. Zusätzliche Software muss nicht aufwändig installiert werden. Das folgende Skript ist zudem sehr einfach gehalten. Es kommt mit weniger als 60 Zeilen PHP-Code aus. Das Skript stellt eine vierstellige Zahl aus -Zeichen mit weißem und schwarzem Hintergrund dar, so wie im folgenden Beispiel:

Matrix mit noch mehr aktivierten Zellen
Jede Ziffer besteht aus einer 3×8-Matrix, deren Elemente, ähnlich der Segment-Anzeige einer Digitaluhr, als Wert eine Zweierpotenz besitzen. Das Funktionsprinzip ist am Ende dieser Vorstellung genauer beschrieben.
Das Skript
Eine Zahl (engl. number) besteht aus einer oder mehreren Ziffern (engl. digits) und so ist auch das Skript aufgebaut. Die Klasse Digit dient dazu, oben genannte Matrix zu erzeugen, welche eine Ziffer darstellt. Sie wird vom “Anwender”, also dem Entwickler, der die Klasse nutzen möchte, nicht direkt angesprochen. Stattdessen benutzt er die Klasse Numbers. Sie erzeugt pro Ziffer ein Digit-Objekt.
Die beiden Klassen sind sehr einfach gehalten und genauso simpel zu benutzen. Sie müssen in die PHP-Datei kopiert oder von einem PHP-Skript per include() oder require() eingebunden werden. Die folgenden drei Zeilen bewirken, dass ein Pseudo-grafisches CAPTCHA mit einer vierstelligen Zufallszahl im Bereich 1000 bis 9999 erzeugt und angezeigt wird.
<?php $n = new Number( rand(1000,9999) ); $n->printNumber(); printf( "<h2>Dargestellt wird die Zahl %d</h2>", $n->getNum() ); ?>
Die Methode Number::getNum() dient dazu, den dargestellten Wert auf einfache Weise weiternutzen zu können. Sinnvoll wäre es beispielsweise, die Zahl in eine temporäre Datei zu schreiben, um sie beim späteren Überprüfen der Formularinhalte mit der Eingabe des Nutzers vergleichen zu können.
Wem das zu einfach ist, sei die folgende Erklärung des Funktionsprinzips ans Herz gelegt. Das Funktionsprinzip zu kennen ist hilfreich, wenn die Klassen verändert oder erweitert werden sollen. Für die Benutzung des Skripts ist dieses Wissen nicht notwendig.
Skript ausprobieren im neuen Fenster oder Skript herunterladen zum
Selbstausprobieren
Erstsemester-Informatik: Funktionsprinzip
Jede Ziffer besteht aus einer 3×8-Matrix. Jede Zelle der Matrix besitzt als “Namen” eine Zweierpotenz, so wie im folgenden Bild dargestellt:

Leere Matrix
Mittels einer Bitmaske wird angegeben, welche Zellen für eine Ziffer aktiviert sein müssen. Um die Bitmaske der Ziffer 1 zu ermitteln, markiert man zunächst in der Matrix einfach alle Felder, die dazu aktiviert sein müssen.

Matrix mit aktivierten Zellen
Bekanntlich kann ein Bit nur zwei logische Zustände haben: 0 oder 1, wahr oder falsch. In der Darstellung ist erkennbar, dass die Felder 22, 24, 25, 28, 211 und 214 aktiviert sein müssen. Die folgende Tabelle zeigt die Zweierpotenzen und die Bits, die in einer Bitmaske für jede dieser Potenzen aktiviert sein müssen.
Die Matrix mit der Darstellung “1″ besitzt also Bitmaske 100100100110100 (Bitmaske A in der Tabelle). Die Dezimaldarstellung ist 18740. Das ist übrigens auch das Ergebnis, wenn man den Taschenrechner 22+24+25+28+211+214 ausrechnen lässt.
| Bit | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
| Basis | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | |
| Dezimal | 16384 | 8192 | 4096 | 2048 | 1024 | 512 | 256 | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 | |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 20 | |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 21 | |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 22 | |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 23 | |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 24 | |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 25 | |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 26 | |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 27 | |
| 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 28 | |
| 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 29 | |
| 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 210 | |
| 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 211 | |
| 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 212 | |
| 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 213 | |
| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 214 | |
| Bitmaske A | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | |
| Bitmaske B | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 1 |
Auf diese Weise ermittelt ein Programmierer die Bitmasken für alle Ziffern. Diese Bitmasken trägt er im Skript direkt ein, damit sie nicht jedes Mal neu ermittelt werden müssen.
Und jetzt rückwärts!
Doch wie kommt das Skript darauf, die Matrix wie eine “1″ aussehen zu lassen, wenn es mit der Bitmaske 100100100110100 (18740 dezimal) gefüttert wird? Das wiederum ist noch simpler, was auch an der Größe des Beispiel-Skripts erkennbar ist: Das Skript klopft jedes der 15 Bits ab und legt die Bitmasken jeder einzelnen Zweierpotenz über die Bitmaske der darzustellenden Zahl. Beispiel: die Bitmaske 111100110100111 (Bitmaske B in der Tabelle) wird Bit für Bit mit den Bitmasken der Zweierpotenzen verglichen. Das erste Bit steht ganz rechts. Zunächst wird 20 mit der Bitmaske B bitweise UND-verknüpft:
000000000000001 (20) 111100110100111 (Bitmaske B in der Tabelle) 000000000000001 Ergebnis
Steht in beiden Bitmasken das – von rechts gezählt – erste Bit auf 1, ist das eine Übereinstimmung. Das Skript weiß nun, dass die Zelle mit der Bezeichnung 20 aktiviert sein muss. Das gleiche wird nun bis 214 fortgeführt. Am Ende steht fest, welche Zellen aktiviert sein müssen: 20, 21, 22, 25, 27, 28, 211, 212, 213 und 214. Das sieht dann so aus:

Matrix mit noch mehr aktivierten Zellen
Soviel zum Funktionsprinzip. Die Kommentare im Skript geben weiteren Einblick in dessen Funktionsweise.
Links zum Thema:
- Dr. Web PLUS: Spam-Abwehr mit CAPTCHAs (€)
- Das gelbe Lexikon: CAPTCHA
- ZIP-Archiv mit Beispielskript (50KB)
Erstveröffentlichung am 03.04.2006



[...] Wer es noch nicht kennt: http://www.drweb.de/magazin/sichere-formulare-teil-3-pseudo-grafisches-captcha-mit-php/ [...]
Dieses Captcha ist sehr einfach zu knacken. Sicherlich ist es eine Art “Nischenprodukt”, will sagen, bietet Sicherheit insofern als es nicht verbreitet ist.
- Sollte es Verbreitung finden dauert die Programmierung eines entsprechenden Skripts sicher maximal zwei Stunden,
- sollte es keine finden, ist der Aufwand es zu knacken doch so niedrig, dass jemand der der entsprechenden Webseite schaden will und etwas programmieren kann die Attacke durchführen wird.
Beste Grüße,
Patrick
@Patrick: Gut erkannt :) Ich habe aber absichtlich nirgendwo im Text erwähnt, dieses Captcha wäre irgendwie sicher. Eine Alternative zu den teilweise recht beliebten Rechenaufgaben als Spam-”Schutz” (ähnlich einfach zu umgehen) ist diese Methode aber schon. Wie so oft gehts beim Umgehen von Sicherheitsmechanismen um eine Kosten-Nutzen-Relation. Lohnt es sich für einen Angreifer, eine Lösung für einen Schutz zu entwickeln? Je mehr Schutzmechanismen es gibt (seien sie auch noch so schwach) erhöhen die Sicherheit für alle, weil Spammer nicht jeden Mechanismus umgehen können. Denn selbst bei einer Entwicklungsdauer von nur einigen Minuten würde es sich nicht lohnen. Der Aufwand wäre im Vergleich zum Nutzen viel zu hoch. Darum gehts hier, nicht um einen Fort Knox an Sicherheit. :)
[...] einigen Jahren habe ich eine Idee für ein Pseudo-Captcha bei Dr. Web [...]