Rechen-Captcha im Eigenbau - Sicher?

Hier werden Probleme rund um das Rechen Captcha behandelt

Moderator: frameguard

Rechen-Captcha im Eigenbau - Sicher?

Beitragvon anihex » 17.05.2010, 06:48

Hi,

nachdem eines meiner Seiten Opfer einer massiven Spam-Attacke befallen wurde, entschied ich mich ein Captcha zu erstellen um diesem entgegen zu wirken. Da mir bekannt ist, dass einige Bots/Skripts Captchas lösen können, wollte ich dieses so gut wie möglich unterbinden.

Ich habe daher folgende Sicherheitsvorkehrungen getroffen:
  • Das Captcha Bild erstellt die Aufgabe nicht, sondern zeigt sie nur an.
  • Das Captcha Bild kann nur von der Seite angezeigt werden, wo es auch angezeigt werden soll.
  • Die Captcha Aufgabe kann eine +, -, * oder / Aufgabe sein.
  • Sowohl die Captcha Aufgabe als auch das Ergebniss werden in $_SESSION gespeichert und mit Blowfish verschlüsselt.
  • Die Abstände zwischen den Zahlen und dem Operator ist immer verschieden.
  • (Kommt noch) Die Zahlen und Operatoren werden als Bilder dargestellt um das Auslesen noch schwerer zu machen.
  • (Kommt noch) Der Hintergrund wird ebenfalls in Form eines Bildes dargestellt.

Reicht das oder hab ich noch etwas vergessen?
Bevor ich es vergesse ... Wörter die in [< und >] eingeschlossen sind, müssen durch den entsprechenden Wert ersetzt werden.
Also z.B.
[<PASSWORT>]
muss durch ein Passwort ersetzt werden. (Die [< und die >] dürfen nicht stehen bleiben!)

Auzug aus der Form-Page
Code: Alles auswählen
   // Direkt am Start eine Session starten
   if ( !empty($_GET["id"]) ) {
      session_id($_GET["id"]);
   }
   session_start();
   $_SESSION["Refer"] = [<REFERER>];

Hier ist dann das Formular.
Das Captcha Bild braucht aber die Session-ID als Parameter.
Das sieht dann in etwa so aus:
Code: Alles auswählen
   <img src="captcha.php?id=<?php echo session_id(); ?>" alt="">

Das Captcha Bild muss jedoch mit ?id=<?php ech

Eine Aufgabe wird mit
Code: Alles auswählen
   Exer( [<PASSWORT>] );
Angelegt und in der Session verschlüsselt gespeichert.

Diese Funktion befindet sich in einer eigenen Datei.
Diese sieht so aus:

exer.php
Code: Alles auswählen
   /* Captcha Functions - (C) 2010 by anihex */
   function Exer($passwort) {
      srand();
      $Fischi = new Blowfish($passwort);

      // Eine zufaellige Aufgabe stellen
      $Op = array();
      $Op[1] = "+";
      $Op[2] = "-";
      $Op[3] = "*";
      $Op[4] = ":";
   
      $Operator = rand(1, 4);
      $Leer1 = rand(1, 3);
      $Leer2 = rand(1, 3);

      $Min = 1;
      $Max = 10;
   
      switch ($Operator) {
         case 1:
            $Zahl1 = rand($Min, $Max);
            $Zahl2 = rand($Min, $Max);
            $Ergebnis = $Zahl1 + $Zahl2;
            break;
         case 2:
            $Ergebnis = rand($Min, $Max);
            $Zahl2 = rand($Min, $Max);
   
            $Zahl1 = $Ergebnis + $Zahl2;
            break;
         case 3:
            $Zahl1 = rand($Min, $Max);
            $Zahl2 = rand($Min, $Max);
            $Ergebnis = $Zahl1 * $Zahl2;
            break;
         case 4:
            $Ergebnis = rand($Min, $Max);
            $Zahl2 = rand($Min, $Max);
   
            $Zahl1 = $Ergebnis * $Zahl2;
            break;
      }
   
      $Leer_1 = "";
      $Leer_2 = "";
   
      for ($Index = 0; $Index < $Leer1; $Index++) {
         $Leer_1 = $Leer_1." ";
      }
   
      for ($Index = 0; $Index < $Leer2; $Index++) {
         $Leer_2 = $Leer_2." ";
      }
   
      $Aufgabe = $Zahl1.$Leer_1.$Op[$Operator].$Leer_2.$Zahl2." = ?";

      $Coded = $Fischi->Encrypt($Aufgabe);
      $_SESSION["id"] = $Coded;
   
      $Coded = $Fischi->Encrypt($Ergebnis);
      $_SESSION["sd"] = $Coded;
   }

   function GetAnswer($passwort) {
      $Fischi = new Blowfish($passwort);
      $Res = $Fischi->Decrypt( $_SESSION["sd"] );

      return $Res;
   }
?>

Das Captcha Bild erwartet nun zum einen die Session-ID und auch eine Variable in der Session, die den Namen "Refer" enthält. Welchen Wert diese Variable haben soll, müsst ihr im Skript nachträglich eintragen.

captcha.php
Code: Alles auswählen
<?php
   /* Captcha Picture - (C) 2010 by anihex */
   /* Modified Tutorial of LLCoolDannY  */

   $Error = 0;

   if ( !empty($_GET["id"]) ) {
      session_id($_GET["id"]);
   } else {
      $Error = 0;
   }

   session_start();
   include ("include/blowfish.php");

   $Blowfishi = new Blowfish( [<PASSWORT>] );
   $Text = $Blowfishi->Decrypt( $_SESSION["id"] );

   if ( $_SESSION["Refer"] != [<REFERER>] ) {
      $Error = 1;
   }

   if ( empty($Text) or $Error ) {
      $Text = "!! ERROR !!";
   }
   Header("Content-Type: image/png");

   $width = 200;
   $height = 40;
   $img = ImageCreate($width, $height);

   $black = ImageColorAllocate($img, 0, 0, 0);
   $white = ImageColorAllocate($img, 255, 255, 255);

   ImageFill($img, 0, 0, $black);
   ImageString($img, 5, 26, 10, $Text, $white);

   ImagePNG($img);
   ImageDestroy($img);

   unset( $_SESSION["Refer"] );
?>


Ob die Antwort korrekt ist, kann man recht einfach prüfen.
Zum Beispiel so:
Code: Alles auswählen
   $answer   = $_POST["answer"];
   $ValidCaptcha = 1;

   // Prüfen, ob die Antwort korrekt ist
   if ( empty($answer) ) {
      // Keine Antwort angegeben
      $ValidCaptcha = 0;
   }

   $correct_answer = GetAnswer( [<PASSWORT>] );

   if ( (int)$answer != (int)$correct_answer ) {
      // Antwort ist falsch
      $ValidCaptcha = 0;
   }


Beispielseite. Funzt auch ;)
Code: Alles auswählen
<?php
   if ( !empty($_GET["id"]) ) {
      session_id($_GET["id"]);
   }
   session_start();
   $_SESSION["Refer"] = "test";

   include "include/blowfish.php";
   include "include/exer.php";
?>
<!DOCTYPE html>
<html>
   <head>
      <meta http-equiv="content-type" content="text/html; charset=UTF-8">
      <title>Captcha Test</title>
   </head>
   <body>
<?php
   if (strtoupper($_SERVER['REQUEST_METHOD']) == "POST") {
      $answer = $_POST["answer"];
      $ValidCaptcha = 1;

      // Prüfen, ob die Antwort korrekt ist
      if ( empty($answer) ) {
         // Keine Antwort angegeben
         $ValidCaptcha = 0;
      }

      $correct_answer = GetAnswer("1234567890");

      if ( (int)$answer != (int)$correct_answer ) {
         // Antwort ist falsch
         $ValidCaptcha = 0;
      }

      if ( $ValidCaptcha ) {
?>
      <p>
         Captcha is valid!
      </p>
<?php
      } else {
?>
      <p>
         Captcha is NOT valid!
      </p>
<?php
      }
   }

   Exer("1234567890")
?>
      <form action="captchatest.php?id=<?php echo session_id(); ?>" method="POST">
         <img src="captcha.php?id=<?php echo session_id(); ?>" alt=""><br>
         <input size="20" maxlength="20" name="answer">
         <input type="submit" value="Check">
      </form>
   </body>
</html>

Testseite

Credits:
Captcha Functions : anihex
Captcha Bild : Tutorial von PHP.de, erweitert durch anihex.
BlowFish Implementierung: PHP-Einfach.de

Wie auch immer ... Ist diese Variante sicher oder ist sie unsicherer als die hier vorgschlagene Version?
anihex
 
Beiträge: 1
Registriert: 17.05.2010, 05:33

Zurück zu Rechen Captcha

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 0 Gäste

cron