Webloginsystem für eigene Anwendungen

  • Hiho,


    es ist ja recht still in der Coding Tutorials-Ecke geworden. Ich wollte schon länger mal ein paar Tutorials schreiben, hatte aber irgentwie nie die Motivation dazu. Mit meiner Teilnahme am Coding-Contest #9 hab ich dann quasi den entscheidenen Schritt getan und ein Basis-Tutorial für eine kleine Tutorial-Reihe geschrieben.


    Es folgt, in leicht verbesserter Form, meine Abgabe zum Coding-Contest #9
    Kritik ist erwünscht.



    [tabmenu]
    [tab='Changelog']
    16.06.11

    • C# Code durch Verwendung von WebClient vereinfacht
    • Design etwas angepasst
    • Geplante Themen hinzugefügt


    [tab='Downloads']
    (Noch) keine Downloads verfügbar
    [tab='Erweiterungen']

    • Umstellung auf XML (in Arbeit)
    • Bruteforce Schutz (in Arbeit)
    • Adminpanel (geplant)
    • Zeitbeschränkungen (geplant)
    • Nutzungsbeschränkungen , IP und HardwareID (geplant)
    • Sicherheitsaspekte (geplant, Themenvorschläge willkommen)
    • Verwenden einer simplen Verschlüsselung (geplant)
    • Verwenden einer symmetrischen Verschlüsselung (geplant)

    Ich werde versuchen die Themen in dieser Reihenfolge abzuarbeiten.
    Weitere Vorschläge sind natürlich willkommen.
    [/tabmenu]



    1. Vorwort
    Um dieses Tutorial zu verstehen benötigt ihr etwas Grundwissen. Ihr solltet mit einem Webspace umgehen können, dass heißt per FTP Dateien hochladen und im Browser aufrufen können und in phpMyAdmin Tabellen erstellen und Datensätze hinzufügen können. Grundlegende PHP-Kenntnisse sind ebenfalls von Vorteil.


    Ein Loginsystem wird meist eingesetzt um Zugriffe zu kontrollieren und/oder zu überwachen.
    Zu einem Loginsystem gehören zwei Komponenten: Ein Client, der sich einloggen möchte, und ein Server, der den Login erlaubt oder verweigert.


    In der Regel programmiert man seinen eigenen Server und lässt den Login über eine TCP Verbindung ablaufen. Das setzt voraus, dass man einen Server im Internet hat, der rund um die Uhr verfügbar ist. Hier kommt man als kleiner Programmierer, der eigentlich nur sein Programm mit einem Login versehen wollte, an seine Grenzen. Entweder man lässt seinen eigenen PC rund um die Uhr laufen oder man mietet sich einen Server der meist gar nicht so billig ist.


    Zum Glück gibt es ja kostenlosen Webspace zu genüge im Internet. Und wie ihr einen solchen Webspace für ein Loginsystem verwendet erfahrt ihr in diesem Tutorial.


    Bevor ihr weiter macht solltet ihr zunächst einen geeigneten Hoster finden.
    Ihr solltet ein paar MB Speicherplatz haben, PHP Unterstützung und eine MySQL Datenbank.


    Für den Server werde ich PHP und SQL verwenden. Für den Clienten liefere ich Beispiele in C# und AutoIt. Ursprünglich wollte ich noch Beispiele zu VB.NET machen, aber die wären Identisch mit den C# Beispielen gewesen. Man kann die Beispiele eigentlich Problemlos nach VB.NET umschreiben.



    2. Theorie




    Der Client (in diesem Fall unser Programm) sendet seine Benutzerdaten an einen Server. Dieser antwortet mit einem Ok oder Nicht Ok.
    Wichtig hierbei ist, dass die Überprüfung der Daten im Server statt findet und nicht im Client. Würde man den Client die Passwörter vergleichen lassen, so müsste man dem Client das richtige Passwort mitteilen. So kann man als User zu jedem Benutzer nur mit dem Benutzernamen das Passwort herausfinden.
    Fazit: Benutzerdatenüberprüfung im Client ist schlecht.
    Server und Client kommunizieren per HTTP-Protokol. Wir werden mit der HTTP-Request-Methode GET die Benutzerdaten an den Server übermitteln.
    Dies ist mit jeder mir bekannten Programmiersprache möglich. Einige bieten sogar vorgefertigte Methoden dafür.


    3. Realisierung
    Wir beginnen mit dem PHP-Script für den Server.
    Das Array $_GET enthält alle per GET übergeben Parameter. Wir werden zunächst ohne Datenbank arbeiten, da das jetzt noch zu kompliziert ist.


    Ob das Ganze auch funktioniert können wir sogar ohne Client testen. Einfach die URL im Webbrowser aufrufen. Auf Groß- und Kleinschreibung ist zu achten.


    http://deineadresse.de/login.p…ich&passwort=meinpasswort


    Wenn man alles richtig gemacht hat, sollte jetzt „Richtig“ ausgegeben werden. Damit wir auch sicher sein können, dass alles geht geben wir einfach einen falschen Benutzernamen oder ein falsches Passwort an.


    http://deineadresse.de/login.p…zer&passwort=meinpasswort
    oder
    http://deineadresse.de/login.p…wort=meinfalschespasswort


    Ich hoffe die Verwendung von GET-Parametern ist nun klar.


    Bei vielen Freehostern wird noch ein Werbelayer eingeblendet. Dieser wird automatisch unserer Ausgabeseite angefügt. Im Moment stört er noch nicht, aber sobald wir mit einem Clientprogramm arbeiten müssen wir die Ausgabe filtern. Dazu später mehr.



    3.1 Datenbankunterstützung
    Das Script kann man nun durch hinzufügen vieler If’s erweitern oder durch ein switch ersetzen. Beides ist viel Schreibaufwand und sehr umständlich zu administrieren.


    Daher werden wir nun die MySQL Datenbank hinzunehmen. Zunächst erstellen wir eine Tabelle. Dazu wählt ihr in phpMyAdmin die passende Datenbank aus und seht daraufhin folgendes:



    Idealerweise nennen wir diese Tabelle users. Die braucht drei Spalten.



    Für Benutzername und Passwort habe ich jeweils maximal 25 Zeichen zugelassen, das sollte mehr als ausreichend sein. Die ID hat einen Maximalwert von 4.294.967.295. Dies ist die maximale Anzahl von Usern die in der Tabelle eingetragen werden können. Die Spalte ID ist außer dem der Primärschlüssel / PrimaryKey.


    Wer möchte kann auch einfach den Query in seiner Datenbank ausführen.
    SQL-Query der Tabelle:

    SQL
    1. CREATE TABLE `users` (
    2. `id` INT( 10 ) UNSIGNED NOT NULL AUTO_INCREMENT ,
    3. `username` VARCHAR( 25 ) CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL ,
    4. `passwort` VARCHAR( 25 ) CHARACTER SET latin1 COLLATE latin1_general_cs NOT NULL ,
    5. PRIMARY KEY ( `id` )
    6. ) ENGINE = MYISAM CHARACTER SET latin1 COLLATE latin1_general_c;



    Zum Testen fügt ihr einfach mit phpMyAdmin zwei bis drei User in die Tabelle ein.




    Nun müssen wir das PHP-Script erweitern:
    1.Verbindung zur Datenbank aufbauen und einloggen
    2.Datenbank auswählen
    3.SELECT-Query zum Server senden
    4.Ergebnis auswerten
    5.Verbindung zur Datenbank abbauen



    Ob alles funktioniert, kann man wieder über die URL testen. Hierbei verwenden wir nicht die Daten vom ersten Script sondern die Daten, die ihr in der Tabelle eingetragen habt.


    Damit haben wir eine funktionierende Grundversion des Loginscripts mit MySQL-Datenbank-Unterstützung.


    3.2 Client
    Wie schon gesagt, bieten viele Programmiersprachen bereits vorgefertigte Methoden um Daten aus dem Internet abzurufen. Für NetFramework-basierende Sprachen ist dies die WebRequest oder WebClient-Klasse. In AutoIt v3 kann man die Funktionen InetRead oder InetGet verwenden.


    Alternativ kann man auch über die Funktion URLDownloadToFile (urlmon.dll) die Datei auf dem Datenträger speichern und danach auslesen.


    In allen Beispielen müsst ihr natürlich die URL an euere Eigene anpassen.


    Wie in 1.2 schon angekündigt, fügen viele Hoster Werbelayer hinzu. Dies ist der Fall wenn die Ausgabe des Logins nicht explizit „Richtig“ oder „Falsch“ ist sondern noch Tags wie <script> dabei stehen.


    Beispiel:



    Auch wenn dies nicht der Fall ist, rate ich euch die nun folgenden Änderungen trotzdem durchzuführen:


    Wir fügen zwei „Split-Tags“ in unsere Ausgabe ein, sodass die Ausgabe ungefähr so aussieht.


    Man könnte an dieser Stelle auch mit XML arbeiten, aber das finde ich für unsere Zwecke etwas überdimensioniert.


    Als Splittag sollte eine Zeichenfolge zum Einsatz kommen, die nicht zufällig in der Ausgabe vorkommen kann (sowohl von eurer Seite, als auch durch den Hoster). Denn dann wäre in dieser Version des Logins das Array vollkommen durcheinander. In diesem Fall, „<splittag>“, ist es relativ unwarscheinlich, dass der Hoster diese Zeichenfolge verwendet.



    Mit einer Split-Funktion splitten wir die Ausgabe in ein Array. Das Array würde dann folgendermaßen aussehen:

    Code
    1. output {
    2. [0] = nichts(leer)
    3. [1] = Richtig
    4. [2] = Der Rest des Dokuments
    5. }


    Achtung in AutoIt ist das Array um ein Feld verschoben da in Feld 0 die Array-Größe steht.


    Daher müssen wir das PHP-Script noch einmal verändern. Aber nur diesen Teil:




    Jetzt sind alle Ausgaben mit den Splittags versehen und wir können mit dem Clienten beginnen.


    3.2.1 AutoIt
    Das Script ist sehr kurz.


    Bitte lasst euch nicht irrtieren das da PHP-Code steht. Ich verwende die php-tags wegen dem Syntax-Highlighting



    In der Funktion DoLogin wird per InetRead unsere Anfrage mit den GET-Parametern an den Server geschickt. Die Antwort des Servers ist der Rückgabewert der Funktion. Zunächst lassen wir den Rückgabewert der Funktion komplett ausgeben.


    Die Ausgabe sollte ähnlich sein.




    Wie man sieht, wird unsere Ausgabe von den Splittags umgeben.
    Also Splitten wir das Ergebnis.


    Auszug aus der AutoIt Hilfe


    Code
    1. StringSplit ( "string", "delimiters" [, flag ] )
    2. Parameters
    3. string The string to evaluate. delimiters One or more characters to use as delimiters (case sensitive). flag [optional] Changes how the string split works, add mutliple flag values together if required:
    4. flag = 0 (default), each character in the delimiter string will mark where to split the string
    5. flag = 1, entire delimiter string is needed to mark the split
    6. flag = 2, disable the return the count in the first element - effectively makes the array 0-based (must use UBound() to get the size in this case).


    In einem AutoIt Array ist das erste ArrayFeld (0) die Array-Größe. Somit beginnen die Daten erst bei Feld 1. Laut dem Beispiel oben wäre unsere Ausgabe dann in Feld 2.
    Das Flag setzen wir auf 1. Dann splittet die Funktion mit dem kompletten Delimiter und nicht mit jedem einzelnen Zeichen.

    PHP
    1. Func DoLogin($username, $password)
    2. $sData = InetRead("http://localhost/cpg/login.php?username=" & $username & "&passwort=" & $password)
    3. $data = BinaryToString($sData)
    4. $output = StringSplit($data, "<splittag>", 1)
    5. return $output[2]
    6. EndFunc


    Den Rückgabewert der Funktion könnt ihr nun mit einem simplen If … Else verarbeiten.
    Unser entgültiger Code sieht nun so aus.




    3.2.2 C# (.NET)
    In .NET-basierenden Sprachen verwendet man WebRequest bzw. HTTPWebRequest oder auch WebClient.
    Als erstes brauchen wir ein GUI.



    Bei .NET ist das ganze ähnlich einfach wie bei AutoIt. Wir erstellen ein Web-Client Objekt (mit dem WebRequest geht es auch, aber dieses ist wesentlich komplexer) und lassen die Ausgabe als String zurückgeben.


    Zunächst die benötigten Verweise:


    C
    1. using System;
    2. using System.Text;
    3. using System.Windows.Forms;
    4. using System.Net;
    5. using System.IO;


    Um einen groben Überblick zu bekommen lassen wir zunächst die komplette Antwort des Servers ausgeben.
    Aus Platzgründen schreibe ich nicht den kompletten Code hin. Ich gehe davon aus, dass ihr einen Button mit einer Funktion belegen könnt.
    Die Ausgabe kann mit einer MessageBox erfolgen.




    So siehts ungefähr aus. Nun müssen wir die Nachricht von den Splittags trennen. Das String-Objekt hat eine integrierte Split-Methode die wir verwenden werden.


    C
    1. string retn = client.DownloadString(targetURL);
    2. // Response splitten
    3. string[] output = retn.Split(new string[]{ "<splittag>" },
    4. StringSplitOptions.None);
    5. // Response zurückgeben
    6. return output[1];


    Wie weiter oben bereits gesagt, wird das Array-Feld 1 die zurückgegeben Daten enthalten. Diese werden wir von der Funktion zurück geben und nun mit einem If … Else behandeln.


    C
    1. string response = DoLogin(txt_user.Text, txt_pass.Text);
    2. if (response == "Richtig")
    3. {
    4. MessageBox.Show("Login ok");
    5. }
    6. else
    7. {
    8. MessageBox.Show("Login falsch");
    9. }


    Die komplette Funktion sieht nun so aus:


    4.Abschluss
    Wir haben nun eine funktionierende Grundlage eines Loginsystems. Es ist auf nahezu jedem Webspace einsetzbar. Wir können eine Datenbank verwenden in der wir realtiv einfach User hinzufügen und entfernen können.


    Als Erweiterung könnte man zum Beispiel weitere Rückmeldungen hinfügen (Passwort falsch, User existiert nicht, Account gesperrt) oder eine Nutzungszeit einfügen oder eine Limitierung der Nutzung auf eine Anzahl von Computern über eine Hardware ID.
    Auch einer besseres Einloggverfahren um Crackern das Leben schwer zu machen wäre sicherlich nicht falsch.
    Am wichtigsten jedoch ist ein Bruteforce-Schutz, der z.B. die IP-Adresse nach mehreren falschen Versuchen bannt.



    Gruß
    florian0

    <p><a href="http://gaben.tv">http://gaben.tv</a></p>

    Dieser Beitrag wurde bereits 2 Mal editiert, zuletzt von florian0 () aus folgendem Grund: [cs] durch [c]-Tags ersetzt, Bild-URLs ersetzt, [headline]-Tags ersetzt, ich hoffe ich pushe nicht -.-