Cooles Personen Captcha

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Cooles Personen Captcha

    Hi alle
    Ich hab eine neue Captcha Sicherung gebastelt und diese funktioniert auch soweit.
    venum-lk.de/captcha/captcha.php?size=s
    Nur hab ich das Problem, dass der Name der ersten Figur ab und zu außerhalb des Bildes beginnt, was meines erachtens aufgrund des Codes eigendlich nicht sein sollte.
    Das Problem tritt hauptsächlich bei der Größe s auf (alle Größen: s, m, l, xl)
    Kann mir da wer helfen?

    Hier der Code

    Quellcode

    1. <?php
    2. // Schriftart (System-ID)
    3. $font = 4;
    4. session_start();
    5. unset($_SESSION['CAPTCHA']);
    6. // Wenn keine Größe angegeben wird
    7. if(!isset($_GET['size'])) $_GET['size'] = "l";
    8. // Das Hintergrundbild laden
    9. $im = imagecreatefrompng("bg_".$_GET['size'].".png");
    10. if(!$im) die("Fehler bei Bildauslesen");
    11. // Namen
    12. if(!@file_exists("names.php")) die("Namensliste nicht vorhanden");
    13. include "names.php";
    14. function randnum($start, $end) {
    15. $numbers = range($start, $end);
    16. srand((float)microtime() * 1000000);
    17. shuffle($numbers);
    18. return $numbers[0];
    19. }
    20. // Farben definieren
    21. $white = imagecolorallocate($im, 255, 255, 255);
    22. $black = imagecolorallocate($im, 0, 0, 0);
    23. // Die Abmessungen des Hintergrundbildes erfassen
    24. $width = imagesx($im);
    25. $height = imagesy($im);
    26. // verfügbare Breite für die drei Personen errechnen
    27. $spacex = $width / 3;
    28. $spacey = 150;
    29. // Bilder in den Verzeichnissen zählen (-2 wegen Navigationszeichen . & ..)
    30. $men = count(scandir("men/")) -2;
    31. $women = count(scandir("women/")) -2;
    32. // Namen zählen
    33. $names_m = count($names[0]) -1;
    34. $names_w = count($names[1]) -1;
    35. // Mann (0) oder Frau (1)
    36. $sex = randnum(0,1);
    37. // Position (1,2,3) auswählen
    38. $position = randnum(1,3);
    39. // Wenn Frau
    40. if($sex) {
    41. // Bilder in PHP einlesen
    42. $pic[1]['s'] = imagecreatefrompng("women/".randnum(1,$women).".png");
    43. $pic[2]['s'] = imagecreatefrompng("men/".randnum(1,$men).".png");
    44. $pic[3]['s'] = imagecreatefrompng("men/".randnum(1,$men).".png");
    45. // Frage erstellen
    46. $question = "Wie heißt die Frau auf diesem Bild?";
    47. // Name 1
    48. $name[1] = $names[1][randnum(0,$names_w)];
    49. // Wenn Mann
    50. }else{
    51. // Bilder in PHP einlesen
    52. $pic[1]['s'] = imagecreatefrompng("men/".randnum(1,$men).".png");
    53. $pic[2]['s'] = imagecreatefrompng("women/".randnum(1,$women).".png");
    54. $pic[3]['s'] = imagecreatefrompng("women/".randnum(1,$women).".png");
    55. // Frage erstellen
    56. $question = "Wie heißt der Mann auf diesem Bild?";
    57. // Name 1
    58. $name[1] = $names[0][randnum(0,$names_m)];
    59. }
    60. // falsche Namen ermitteln
    61. // Name 2
    62. $temp = randnum(0,1);
    63. $count = $names_m;
    64. if($temp) $count = $names_w;
    65. $name[2] = $names[$temp][randnum(0,$count)];
    66. // Name 3
    67. $temp = randnum(0,1);
    68. $count = $names_m;
    69. if($temp) $count = $names_w;
    70. $name[3] = $names[$temp][randnum(0,$count)];
    71. // Bildabmessungen (BxH) ermitteln
    72. $pic[1]['w'] = imagesx($pic[1]['s']);
    73. $pic[1]['h'] = imagesy($pic[1]['s']);
    74. $pic[2]['w'] = imagesx($pic[2]['s']);
    75. $pic[2]['h'] = imagesy($pic[2]['s']);
    76. $pic[3]['w'] = imagesx($pic[3]['s']);
    77. $pic[3]['h'] = imagesy($pic[3]['s']);
    78. // Laufparamteter für falsche Personen
    79. $j = 2;
    80. // Die Positionen durchlaufen
    81. for($i=1;$i<4;$i++) {
    82. // Wenn aktuelle Position nicht die ermitellte Position
    83. if($i != $position) {
    84. // x und y Koordinaten der Figur ermitteln
    85. $pic[$j]['x'] = randnum(($i-1)*$spacex+1,$i*$spacex-$pic[$j]['w']-1);
    86. $pic[$j]['y'] = randnum(1,$spacey-$pic[$j]['h']-1);
    87. // Figur in das Bild einfügen
    88. ImageCopy($im, $pic[$j]['s'], $pic[$j]['x'], $pic[$j]['y'], 0, 0, $pic[$j]['w'], $pic[$j]['h']);
    89. // Namen auf Position speichern
    90. $n[$i]['na'] = $name[$j];
    91. // Länge (pixel) des Names ermitteln
    92. $n[$i]['le'] = imagefontwidth($font)*strlen($n[$i]['na']);
    93. // Koordinaten des Namensrechteck ermitteln
    94. $n[$i]['x1'] = randnum($pic[$j]['x'], $pic[$j]['x']+$pic[$j]['w']-$n[$i]['le']);
    95. $n[$i]['y1'] = randnum($pic[$j]['y'], $pic[$j]['y']+$pic[$j]['h']-20);
    96. // Zähler hochsetzen
    97. $j++;
    98. // Wenn aktuelle Position die ermitellte Position
    99. }else{
    100. // x und y Koordinaten der Figur ermitteln
    101. $pic[1]['x'] = randnum(($i-1)*$spacex+1,$i*$spacex-$pic[1]['w']-1);
    102. $pic[1]['y'] = randnum(1,$spacey-$pic[1]['h']-1);
    103. // Figur in das Bild einfügen
    104. ImageCopy($im, $pic[1]['s'], $pic[1]['x'], $pic[1]['y'], 0, 0, $pic[1]['w'], $pic[1]['h']);
    105. // Namen auf Position speichern
    106. $n[$i]['na'] = $name[1];
    107. // Länge (pixel) des Names ermitteln
    108. $n[$i]['le'] = imagefontwidth($font)*strlen($n[$i]['na']);
    109. // Koordinaten des Namensrechteck ermitteln
    110. $n[$i]['x1'] = randnum($pic[1]['x'], $pic[1]['x']+$pic[1]['w']-$n[$i]['le']);
    111. $n[$i]['y1'] = randnum($pic[1]['y'], $pic[1]['y']+$pic[1]['h']-20);
    112. }
    113. }
    114. // Namen in das Bild einfügen
    115. for($i=1;$i<4;$i++) {
    116. // x2 & y2 errechnen
    117. $n[$i]['x2'] = $n[$i]['x1'] + $n[$i]['le'] + 8;
    118. $n[$i]['y2'] = $n[$i]['y1'] + 20;
    119. // Wenn x2 & y2 außerhalb des Bildes
    120. if($n[$i]['x2'] > $width-1) {
    121. $n[$i]['x1'] = $width-$n[$i]['le']-9;
    122. $n[$i]['x2'] = $width-1;
    123. }
    124. if($n[$i]['y2'] > 148) {
    125. $n[$i]['y1'] = 128;
    126. $n[$i]['y2'] = 148;
    127. }
    128. // Rechteck zeichnen
    129. imagefilledrectangle($im, $n[$i]['x1'], $n[$i]['y1'], $n[$i]['x2'], $n[$i]['y2'], $white);
    130. // Namen schreiben
    131. imagestring($im, $font, $n[$i]['x1']+4, $n[$i]['y1']+2, $n[$i]['na'], $black);
    132. }
    133. // Die linke Position der Frage errechnen
    134. $leftquestpos = ( $width - imagefontwidth($font)*strlen($question) )/2;
    135. // Die Frage schreiben
    136. imagestring($im, $font, $leftquestpos, $height-18, $question, $white);
    137. // Session String mit Namen füllen
    138. $_SESSION['CAPTCHA'] = $name[1];
    139. // BILD AUSGEBEN
    140. // Dem Browser die Bildart (png) mitteilen
    141. Header('Content-type: image/png');
    142. // Das png-Bild ausgeben
    143. imagepng($im);
    144. // Speicher freigeben
    145. imagedestroy($im);
    146. ?>
    Alles anzeigen


    Vielen Dank
    daLu
  • Hallo alle zusammen
    Ich hab den Fehler jetzt selber gefunden.

    Der Fehler lag bei Zeile 126 in meinem vorherigen Code

    Quellcode

    1. // Koordinaten des Namensrechteck ermitteln
    2. $n[$i]['x1'] = randnum($pic[$j]['x'], $pic[$j]['x']+$pic[$j]['w']-$n[$i]['le']);


    Wenn hier $n[$i]['le']), also die Länge des Namens zu groß ist, dann kann auf der ersten Figurenposition ein x-Koordinatenbereich in den Zufallsgenerator gegeben werden, der bei 1 beginnt und ins Negative läuft.

    Ich hab das jetzt folgendermaßen korrigiert

    Quellcode

    1. // Prüfen ob Namensrechteck auserhalb des Bildes liegt
    2. $x2 = $pic[$j]['x']+$pic[$j]['w']-$n[$i]['le'];
    3. if($x2 < $pic[$j]['x']) $x2 = $pic[$j]['x'];
    4. // Koordinaten des Namensrechteck ermitteln
    5. $n[$i]['x1'] = randnum($pic[$j]['x'], $x2);


    Ich hab das Ganze in einen Dateianhang gepackt, wenn es jemand haben will.
    Ich wäre auch sehr dankbar, wenn ich Verbesserungsvorschläge bekommen würde :)

    MfG
    daLu
    Dateien
    • captcha.zip

      (80,8 kB, 240 mal heruntergeladen, zuletzt: )

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von venum-lk () aus folgendem Grund: Neuen Code hochgeladen

  • Mein erstes Kommentar dazu ist: Das Captcha ist total cool und kreativ! So cool, dass ich überlege es bei easy-coding einzubauen.
    Hast du dir das selbst ausgedacht oder irgendwo gesehen?

    Einziges Problem ist halt, dass ich dann die Namensliste nicht öffentlich machen kann. Taugt also nicht unbedingt für ein Open Source Script.
    Bilder
    • personen-captcha.png

      12,09 kB, 451×171, 237 mal angesehen
  • Hehe, das gleiche Captcha habe ich mir auch mal zusammengebastelt. Abgeschaut ist es von 3dl.am, auch wenn der Threadstarter das vielleicht (aus gewissen Gründen) gern vergessen würde ;)

    Mit der Namensliste habe ich mich auch schwer getan. Es müssen zum einen sehr viele Namen sein. Zum anderen müssen recht viele Namen dabei sein, die nicht eindeutig Mann oder Frau zuordenbar sind. So ist ja die Grundidee... Wobei man es auch mit "normalen" Namen hinbekommen kann, da ja die Kombination aus Bild und Eingabe wichtig ist.

    Meine Implementationhat zwei kleine Fehler. Ich habe den Namen immer an der gleichen Stelle erscheinen lassen und meine genutzten Grafiken sind immer gleich. So wurde das Captcha nach 2h geknackt.
    Verändert man diese beiden Schwachpunkte, so erhöht sich die Anzahl der möglichen Kombinationen. Arbeitet man dann noch die Namensliste auf, so wird es fast unschlagbar.
    Auf der Ursprungsseite reichte aber auch das nicht. Da war es nötig das Erscheinen des Captchas mit einem Ajax-Call zu realisieren. Man muss also erst einmal klicken bevor die Box mit den Bildchen erscheint. Sicher auch automatisierbar, jedoch noch ein Schritt mehr zur Lösung des Problems.

    // Edit: noch eine Idee zur Namensliste: Eventuell sollte man sich eine Strategie überlegen, wie man die Namen nutzt. Man könnte zum Beispiel einige Namen monatelang nicht nutzen, dann umschalten. Ich würde das als Windowing-Strategie bezeichnen. Man nutzt immer nur ein Fenster (Ausschnitt) der Liste. Das geht natürlich nur, wenn die Liste groß genug ist. Ich hatte bei mir das Problem, dass die recht kleine Liste schnell ausgelesen wurde...

    P.S. Wenn das Erwähnen der Ursprungsseite nicht erlaubt ist, dann bitte rausnehmen...
  • Erwischt ;)
    Aber deine (mad) Probleme mit der zufälligen Anordnung auf dem Bild hab ich meiner Meinung gelöst :)
    Die Namensliste lässt sich leicht noch erweitern (derzeit sind es ca 350 bei mir), außerdem werden den "falschen" Personen zufällig männliche oder weibliche Namen zugeordnet, also müssen sich männliche und weibliche Namen nicht gleichen.
    Der Ajax-Call sollte auch nicht des Problem sein

    Und wenn du die Namen jetzt komplett ausschalten willst, dann mach halt eine Frage alla "Wie heißt der Deckname des weiblichen Spions ... ?" und gib im eine zufällige Zeichenkombination als Namen :D

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von venum-lk ()

  • Ich versteh das Problem mit der Namensliste nicht. Was bringt es nem Bot, wenn er diese hat? Einfach einen davon auszuprobieren ist nicht sehr erfolgsversprechend, wenn die Liste mehrere hundert Einträge hat und nach jedem Fehlversuch ein neues Captcha erzeugt wird. Da ist es doch einfacher OCR-mäßig die 3 Namen einzulesen und einen davon zu probieren. Die wahrscheinlichkeit für einen Treffer steigt aufjedenfall immens.

    Ich würde im übrigen nur Männer oder nur Frauennamen in einem Bild verwenden. Der User soll das Geschlecht ja übers Bild und nicht über den Namen erkennen oder nicht?
  • Also bei mir ist das so, ich habe männliche und weibliche Namen und Namen, die nicht eindeutig zugeordnet werden können (z.B. Andrea). Wenn ein Bot diese Übersicht hätte (also auch mit den Geschlechtszuordnungen), dann wäre das Captcha umsonst. Da man diesen Ansatz bei einer Open Source-Lösung (wie d0nut oben beschrieb) veröffentlicht, wäre es kein Problem einen Bot zu schreiben.

    Erhöht man jedoch die Kombination aus Figur + Kästchen (am besten mit Zufallsposition) + Namen (große Liste), dann ist es schon ein bisschen schwerer für einen Bot.

    @venum-lk: Das wäre dann ja reines OCR+raten, würde also dadurch lösbar sein, dass der Bot nur trainiert, wann "frau/weiblich" und wann "mann/männlich" die richtige Kombination und somit die Lösung bringt. Ich glaube das obere Beispiel ist viel komplexer. Kann man auch ausrechnen, aber nicht mehr jetzt ;)