[Sicherheit] Captcha mit PHP und MySQL programmieren

Wir programmieren uns hier einen Captcha Bestätigungscode, der uns vor Spam schützt. Diesen kombinieren wir mit einer Datenbank um verschiedene Fragen zu erhalten.

Wir schauen uns als erstes den kompletten Code einmal an und pflücken in hinterher auseinander.

index.php (Seite, in der die Bestätigung eingegeben werden soll Kontaktformular o.ä.)

 

<?php
  session_start();
?>
<!DOCTYPE html>
<html>
	<head>
		<title>Kontakt</title>			
	</head>
	<body>
       <div id="wrapper">       	  	  
       	  <div id="main">
       	  	<div id ="text">
<?php

$connect = mysql_connect ("localhost", "root", "") or die('Fehler beim Aufbau der Verbindung');
mysql_select_db("catcha") or die ("Die Datenbank existiert nicht."); 

$query = @mysql_query("SELECT frage, antwort FROM captcha ORDER BY RAND() LIMIT 1;");

$result = @mysql_fetch_array($query) or die( '
<div id="text"><p id="sorrybenutzer2">Sorry, aber dieser Benutzername existiert nicht!<br />
<ahref="index.php">Zurück</a></p></div>');

$antwort = $result['antwort'];

$kleinbuchstaben = strtolower($antwort);

$_SESSION['frage'] = $result['frage'];   
$_SESSION['antwort'] = $kleinbuchstaben; 

echo "<form method='post' id='registrierung' action='uberprufung.php'>
      <p>Deine Name: <input type='text' name='name' maxlength='50'></p>
      <p>Deine Email Adresse: <input type='text' name='email' maxlength='50'></p>
      <p>Deine Nachricht: <input type='text' name='nachricht' maxlength='500'></p>
      <h4>Sicherheitsfrage</h4>
      <p>Frage: ". $result['frage'] ."</p>
      <input type='text' name='antwort' maxlength='50'>
      <input type='submit' name='button' value='Absenden'></form>";

?>

       	  	</div>
       	  </div>    
       </div>
	</body>
</html>

Überprüfung.php (Welche uns das Kontaktformular sendet, aber vorher überprüft, ob der Captcha richtig eingegeben wurde)

<?php
  session_start();
?>
<!DOCTYPE html>
<html>
	<head>
		<title>Kontakt</title>			
	</head>
	<body>
       <div id="wrapper">       	  	  
       	  <div id="main">
       	  	<div id ="text">
<?php

$antwort = $_POST['antwort'];

$kleinbuchstabenantwort = strtolower($antwort);

if ($_SESSION['antwort'] != $kleinbuchstabenantwort) {
    echo "Der Bestätigungs-Code ist leider falsch.";
}

elseif ($_SESSION['antwort'] == $antwort) {

    $text = $_POST['nachricht'];
    $email = $_POST['email'];
    $betreff = "Kontaktanfrage!";
    $from = $_POST['name'];
    $empfanger = "[email protected]";

    mail($empfanger, $betreff, $text, $from);

    echo "Deine Anfrage wurde versendet!";

session_unset();
session_destroy();
unset($_SESSION['antwort']);
unset($_SESSION['frage']);

}
else {
	echo "Unbekannter Fehler";
}
?>

       	  	</div>
       	  </div>    
       </div>
	</body>
</html>

 


Nehmen wir nun zuerst die index.php auseinander:

Die ersten beiden Zeilen unserer index.php starten schon mal eine sog. „Session“. In dieser können wir Variablen abspeichern und auf der nächsten Seite wieder auslesen. Diese funktionieren ähnlich wie Cookies, können aber im Gegensatz zu Cookies auch nicht vom Benutzer geändert werden.

Wir starten die Session mit folgender Anweisung, die möglichst am Anfang des Dokumentes stehen sollte.

<?php
  session_start();
?>

Der nächste Teil des Dokumentes sollte jedem bekannt sein. Diesen werde ich nicht weiter erläutern.

<!DOCTYPE html>
<html>
	<head>
		<title>Kontakt</title>			
	</head>
	<body>
       <div id="wrapper">       	  	  
       	  <div id="main">
       	  	<div id ="text">

Der nächste Befehl baut schon mal die Verbindung zu unserer Datenbank auf.

$connect = mysql_connect ("localhost", "root", "123456") or die('Fehler beim Aufbau der Verbindung');
mysql_select_db("captcha") or die ("Die Datenbank existiert nicht.");

Wir speichern diese in der Variable $connect ab. Wir ersetzen „localhost“ durch die Serveradresse, „root“ durch den Benutzernamen und „123456“ durch unser Passwort.

Der Befehl „Die“ bedeutet, wörtlich übersetzt, „sterben“. Heißt so viel wie, wenn die Datenbank nicht erreicht werden konnte, soll das Script „sterben“ und sich nicht weiter ausführen. Also werden alle unsere PHP, MySql und auch alle HTML und CSS Anweisungen ignoriert und nicht ausgeführt.

Mit mysql_select_db wählen wir unsere Datenbank aus. Auch hier ist wieder der Befehl „die“ vorhanden.

Als nächstes starten wir unsere Datenbankabfrage.

$query = @mysql_query("SELECT frage, antwort FROM captcha ORDER BY RAND() LIMIT 1;");

$result = @mysql_fetch_array($query) or die('Fehler!');

Wir speichern unsere Abfrage in der Variable $query ab. Unsere Abfrage heißt so viel wie: „Wähle Frage, Antwort aus der Tabelle captcha geordnet bei Zufällig nur 1 anzeigen.“

Er wählt uns also zufällig einen Datensatz aus der Datenbank aus und zeigt diesen an.

In unserer Datenbank müssen also 3 Spalten angelegt sein. Einmal unseren Primärschlüssel mit der ID und Auto Increment. Einmal die Frage und einmal die Antwort. In die Frage Spalte wird die Frage eingetragen und in die Antwort Spalte die Antwort.

Mit $result speichern wir unser Ergebnis aus der Datenbank in einem Array ab. Dieses Array nennt sich nun $result[“].

Nun speichern wir Variablen in einer Session ab und fragen unsere Antwort ab.

$antwort = $result['antwort'];

$kleinbuchstaben = strtolower($antwort);

$_SESSION['frage'] = $result['frage'];   
$_SESSION['antwort'] = $kleinbuchstaben;

Unsere Variable $antwort ist nun gleich die Spalte „Antwort“ aus unserer Datenbank.

Unser Befehl „strtolower“ bewirkt, dass wir unsere Variable $antwort komplett in Kleinbuchstaben schreiben. D.h. wenn unsere Variable Antwort vorher „Hallo IcH bIn eiNe AntWort“ war ist sie nach der Konvertierung „hallo ich bin eine antwort“. Dies bewirkt das Groß und Kleinschreibung bei dem Captcha keine Rolle spielt.

Mit den Befehlen $_SESSION speichern wir unsere Frage und unsere Antwort ab, damit wir diese Variablen auf unserer überprüfung.php noch zur Verfügung haben, da wir diese nicht erneut abfragen können. (weil die Einträge ja zufällig gewählt werden)

echo "<form method='post' id='registrierung' action='uberprufung.php'>
      <p>Deine Name: <input type='text' name='name' maxlength='50'></p>
      <p>Deine Email Adresse: <input type='text' name='email' maxlength='50'></p>
      <p>Deine Nachricht: <input type='text' name='nachricht' maxlength='500'></p>
      <h4>Sicherheitsfrage</h4>
      <p>Frage: ". $result['frage'] ."</p>
      <input type='text' name='antwort' maxlength='50'>
      <input type='submit' name='button' value='Absenden'></form>";

Mit unserem Echo Befehl geben wir unser Formular in HTML aus. Wir setzen hier unsere Variable $result[‚frage‘] ein, die der Spalte „Frage“ aus der Datenbank entspricht.

 


Nun kommen wir zu der Überprüfung.php

Auch hier starten wir zunächst die Session, damit wir unsere Frage und unsere Antwort wieder auslesen können.

<?php
  session_start();
?>

Der nächste Teil dürfte wieder bekannt sein.

Nun wird es aber wieder interessant.

Als erstes holen wir unsere Antwort via $_POST von der index.php und konvertieren diese ebenfalls mit „strtolower“ in Kleinbuchstaben.

$antwort = $_POST['antwort'];

$kleinbuchstabenantwort = strtolower($antwort);

Wir schreiben uns eine If-Abfrage, die überprüft ob der Captcha richtig eingegeben wurde.

if ($_SESSION['antwort'] != $kleinbuchstabenantwort) {
    echo "Der Bestätigungs-Code ist leider falsch.";
}

Diese bedeutet so viel wie, Ist die Variable $_SESSION[‚antwort‘] nicht dasselbe wie die Variable $kleinbuchstaben soll er uns einen Text Ausgeben.

Die Variable $_SESSION[‚antwort‘] entspricht dem Feld Antwort aus unserer Datenbank. Die Variable $kleinbuchstaben ist unsere Antwort, die ins Formular geschrieben wurde.

Wenn hier nun alles glatt gelaufen ist und unser Captcha richtig eingegeben wurde, geht es zur nächsten Abfrage. Aus Sicherheitsgründen nehmen wir hier eine „elseif“ Abfrage und kein normales „else“. „Elseif“ bedeutet so viel wie, wenn das erste nicht zutrifft dann eventuell das. Es lassen sich beliebig viele elseifs hintereinander weg schreiben.

elseif ($_SESSION['antwort'] == $kleinbuchstaben) {

    $text = $_POST['nachricht'];
    $email = $_POST['email'];
    $betreff = "Kontaktanfrage!";
    $from = $_POST['name'];
    $empfanger = "[email protected]";

    mail($empfanger, $betreff, $text, $from);

    echo "Deine Anfrage wurde versendet!";

Heißt nun so viel wie: wenn $_SESSION[‚antwort‘] das gleiche ist wie $kleinbuchstaben soll er unsere Email abschicken.

Den Formular Teil brauche ich nicht weiter erläutern, da dieser bekannt sein sollte.

Nun löschen wir noch schnell den Session Speicher und schließen die elseif Abfrage.

session_unset();
session_destroy();
unset($_SESSION['antwort']);
unset($_SESSION['frage']);

}

Nun geben wir dem ganzen noch eine Else Anweisung, falls beide if´s nicht zutreffen, damit der User wenigstens eine Fehlermeldung bekommt.

else {
	echo "Unbekannter Fehler";
}

Und fertig ist unsere Captcha Abfrage vor einem Formularfeld. Diese lässt sich natürlich auch auf alles andere anwenden. Die Dateien lassen sich im Downloadbereich herunterladen.
http://marvins-blog.de/blog/2014/01/15/kontaktformular-mit-captcha-abfrage-datenbankgestuetzt/

Marvin Sengera

Hey! Ich bin Marvin Sengera, Inhaber der Internetagentur "Binärfabrik" aus Paderborn. Ich habe mein Bachelorstudium Informatik mit Schwerpunkt Industriespionage an der Hochschule Hamm Lippstadt abgeschlossen und absolviere derzeit meinen Master in Fachrichtung "Technical Entrepreneurship and Innovation". Ich beschäftige mich rund um die Themen Informatik, Innovation & Unternehmensgründung.

Das könnte dich auch interessieren …

2 Antworten

  1. Matthias sagt:

    Bis auf

    session_unset();
    session_destroy();

    ganz okay. Das macht man am besten nur, wenn man die Session wirklich zu nichts anderem mehr braucht. Ich würde es weg lassen…

    Ich habe so etwas ganz ohne mySQL gebaut und Bildern, welche mit GD gerendert werden und zahlen enthalten. Eventuell schreibe ich dazu ja auch noch ein Tutorial. Ist schon Jahre her. Ist eh die Frage, ob das heutzutage noch jemand selbst schreibt, oder lieber bestehende Dienste nutzt.

    • Das stimmt. In meinem Beispiel wird die Session restlos gelöscht. Auch anderweitig gesetzte Sessions werden gelöscht. Es wird in diesem Beispiel die Session Variable sozusagen zurückgesetzt.
      Ich gebe dir aber Recht, es ist sinnvoll diese Zeilen Code weg zu lassen um spätere Session Fehler zu vermeiden.

      Ich glaube schon das einige Programmierer so etwas noch selber programmieren. Auch für Anfänger in diesem Bereich ist das eine gute Übung. Klar gibt es auch fertige Dienste dafür, aber selbst programmiert hat man immer mehr Kontrolle über die Anwendung und die Implementierung, im Gegensatz zu fertigen Diensten.

Schreibe einen Kommentar