Archiv verlassen und diese Seite im Standarddesign anzeigen : Browsergames (Techniken)
Hallo,
Ich habe mir mal vorgenommen (so unglaublich es auch klingen mag) ein Browsergame zu programmieren.
Wenn ich scheitere - was solls, aber einen Versuch sollte es Wert sein.
Allerdings bin ich noch nicht so richtig in der Materie und wollte mich vorher nocheinmal informieren.
- Welche PHP Funktionen müssen definitiv freigeschaltet sein?
- Grobprinzip der Rohstoffberechnung
- Generelle Information zu zeitgesteurten Scripts
- Weitere Beachtungen / Besonderheiten ?
Wäre nett, wenn ihr mir hierfür einige Infos geben könnt (ich verlange nichtmal nen Code)
Achja und bitte sagt mir nicht, was ich nicht tun kann ^^
1. Im Zweifelsfall alle. Wenn du keinen eigenen Server hast, wird die Sache eh schwer.
2. Gibt mehrere Ansätze. Entweder bei jeder Abfrage den neuen Wert aus der verstrichenen Zeit seit der letzten Abfrage berechnen oder einen Cronjob laufen lassen. Letzteres ist genauer, konzentriert aber die Rechenleistung auf einige wenige Zeitpunkte, was dazu führen könnte, dass der Server zu diesen Zeitpunkten kaum noch erreichbar ist.
3. Wahlweise Cronjobs oder ein eventbasiertes System, bei dem du Aktionen mit Timestamps in eine Datenbank speicherst und bei jedem Seitenaufruf alle Aktionen ausführst, deren Timestamps in der Vergangenheit liegen
4. Nimm dir viel Zeit und ein gutes Team
Jesus_666
17.12.2006, 12:12
4.) Arbeite NIE NIE NIE mit Userinput, den du nicht gefiltert hast. Wenn du nicht sicherstellst, daß jegliche Daten, die die User schicken, ungefährlich gemacht wurde, kannst du böse Probleme kriegen. Beispiel:
$result = mysql_query('SELECT * FROM `users` WHERE id = '.$_GET['id']);
Wenn der User jetzt für id den Wert "1; DELETE FROM `users`" sendet und du die Datenbank nicht so konfiguriert hast, daß du kein DELETE machen darfst darfst (arg unwahrscheinlich) sind plötzlich sämtliche User aus der DB verschwunden.
SQL Injection ist mit schlecht programmierten Webanwendungen verdammt einfach und in der Regel liegst's daran, daß dem User vertraut wurde, die richtigen Daten zu senden.
Wie kann man die Daten, die die User schicken, denn ungefährlich machen?
Blakkeight
17.12.2006, 12:30
Hm das wuerde mich aber auch mal Interessieren, denn ich mache es nur so. ;(
4.) Arbeite NIE NIE NIE mit Userinput, den du nicht gefiltert hast. Wenn du nicht sicherstellst, daß jegliche Daten, die die User schicken, ungefährlich gemacht wurde, kannst du böse Probleme kriegen. Beispiel:
$result = mysql_query('SELECT * FROM `users` WHERE id = '.$_GET['id']);
Wenn der User jetzt für id den Wert "1; DELETE FROM `users`" sendet und du die Datenbank nicht so konfiguriert hast, daß du kein DELETE machen darfst darfst (arg unwahrscheinlich) sind plötzlich sämtliche User aus der DB verschwunden.
SQL Injection ist mit schlecht programmierten Webanwendungen verdammt einfach und in der Regel liegst's daran, daß dem User vertraut wurde, die richtigen Daten zu senden.
Also aus deinem Post verstehe ich, dass man Userdaten nicht mit Get übergeben soll, nunja das wäre auch ziemlich unsicher, muss ich zugeben.
Aber wie kann ein User aus einem Select ein Delete machen?
Verstehe ich nicht, hängt wohl unmittelbar damit zusammen, dass ich keine Ahnung von Injections
habe.
@DFYX
Eigener Server? Das wird recht teuer. Für allgemeine Performance wäre es schon nützlich, aber wieso sollte ich mir einen Server kaufen, wenn ich nicht mal weiß, ob mir mein Projekt gelingen wird.
Würde dann eventuell folgen..
@Zeitgesteuerte Scripts
Gibts nicht auch eine gute Möglichkeit, um eben diese Scripts zu realisieren, ohne mein eigenes Zutun (Aktualisierungsdatei aufrufen), oder Cronjobs zu verwenden?
Jesus_666
17.12.2006, 13:22
Dazu zahlt es sich aus, erst mal zu wissen, wie die Syntax von SQL aufgebaut ist und welche Zeichen als gefährlich einzustufen sind. Anschließend sorgt man dafür, daß diese Zeichen nicht auftauchen, beispielsweise über strtr(). Das hat auch den schönen Nebenefffekt, daß man besser in SQL wird.
Wer nicht so viel Aufwand betreiben will kann sich auch einfach Ratschläge zum vermeiden von Injections einholen. Schönerweise wird PHP mal wieder seinem Ruf gerecht, eine exzellente Dokumentation zu haben und bietet eine Seite (http://de3.php.net/manual/de/security.database.sql-injection.php), die gängige SQL Injection-Methoden erklärt und Gegenmaßnahmen anzeigt. Mit diesen Informationen sollte es einfach sein, eine ziemlich sichere Seite zu bauen. Lest vor Allem auch die Userkommentare unten!
Edit:
Also aus deinem Post verstehe ich, dass man Userdaten nicht mit Get übergeben soll, nunja das wäre auch ziemlich unsicher, muss ich zugeben.
Aber wie kann ein User aus einem Select ein Delete machen?
Verstehe ich nicht, hängt wohl unmittelbar damit zusammen, dass ich keine Ahnung von Injections
habe.
Sieh' dir mein Beispiel an. Ich habe einfach an den übergebenen Wert ein Semikolon und einen neuen Befehl angehängt. Das Semikolon bedeutet bei SQL, daß der Befehl zuende ist und ein neuer folgt. Ich habe also mal eben aus einem Befehl zwei gemacht.
Man braucht für diese Art von Angriff natürlich gewisse Kenntnisse über die Struktur der vom Skript verwendeten Befehle, aber die kann man sich auch besorgen (die meisten PHP-Seiten leiten Datenbankfehler einfach an den User weiter, also kann der Angreifer einfach in ein Feld Müll eintragen und sich den Fehler ansehen).
BTW, auch POST-Daten lassen sich manipulieren. Man sollte grundsätzlich alles, was der User sendet, mit Mißtrauen behandeln. In Onlineanwendungen gibt es keine Paranoia, nur Vorsicht.
Eine einfache Methode wäre, alle numerischen Werte durch intval() und Strings durch addslashes() oder mysql_escape_string() zu jagen und grundsätzlich alle Werte, die übergeben werden in ' ' zu schreiben. Dann kriegt der User im schlimmsten Fall falschen Output, aber die Datenbank bleibt heil.
Den eigenen Server habe ich aus mehreren Gründen empfohlen:
Die meisten Freehoster bieten nicht die nötige Datenbankgröße und die nötige Rechenleistung
Ich kenne keinen Freehoster, bei dem man Cronjobs laufen lassen kann
Bei den meisten Freehostern sind Browsergames gar nicht erlaubt.
Gibts nicht auch eine gute Möglichkeit, um eben diese Scripts zu realisieren, ohne mein eigenes Zutun (Aktualisierungsdatei aufrufen), oder Cronjobs zu verwenden?
Wie gesagt, schreib Events mit Typ und Timestamp in eine Tabelle und hol sie dir bei jedem Seitenaufruf mit SELECT * FROM `events` WHERE `timestamp` <= UNIX_TIMESTAMP() ORDER BY `timestamp` ASC. Dann kannst du sie der Reihe nach verarbeiten und überall, wo du normalerweise time() verwenden würdest $row['timestamp'] verwenden. Der einzige Nachteil ist, dass die Seitenaufrufe ggf. recht lange dauern.
Edit:
Evtl. wäre es sogar besser nicht UNIX_TIMESTAMP() zu verwenden. Schließlich musst du die Einträge hinterher auch löschen und wenn du da den Timestamp wieder neu generieren lässt, könntest du schon eine Sekunde weiter sein und damit im schlimmsten Fall Events unbearbeitet löschen. Speicher den also lieber in PHP mit time() in ne Variable und übergeb die.
Den eigenen Server habe ich aus mehreren Gründen empfohlen:
Die meisten Freehoster bieten nicht die nötige Datenbankgröße und die nötige Rechenleistung
Ich kenne keinen Freehoster, bei dem man Cronjobs laufen lassen kann
Bei den meisten Freehostern sind Browsergames gar nicht erlaubt.
Dachte ich mir doch, dass ich dich falsch verstanden habe.
Du redest von kommerziellem Webspace, aber ich dachte du meinst, dass ich wirklich einen Server mieten soll, das ist ja AFAIK ein Unterschied.
Gut, denn kommerzieller Webspace ist nicht sonderlich teuer, da bekommt man schon guten für 3 Euro im Monat.
Events?
addslashes() wird ohnehin ein wichtiges Thema werden, da Magic Quotes abgeschafft werden. Yay.
Die andere Funktion heißt mysql_real_escape_string(), ist aber alleinstehen auch nicht sehr nützlich.
Wenn der User eine vierstellige Jahreszahl eingeben soll, muss man prüfen, ob das Eingabefeld überhaupt gegeben ist, ob es sich um eine Zahl handelt, ob sie 4 stellen hat, eventuell ob es ein gültiges Jahr ist (nicht etwa 2008, außer bei bestimmten Anwendungen).
Strings sind .. anders. Da hilft die oben genannte Funktion schon, aber dann muss man immernoch den Inhalt validieren. D.h. bei der Ein- eventuell auch bei der Ausgabe bestimmte Zeichen überprüfen und ggf. ersetzen. Z.B. <script> Bereiche oder javascript: in URIs, je nach Schema eben.
Kleine Ergaenzung am Rande: einige Leute uebersehen gerne, dass Cookies auch User-Input sind. Ich hab schon mehr als einmal 'ne Webanwendung gesehen, die zwar GET- und POST-Parameter filtert, bei der aber SQL-Injections ueber manipulierte Cookies moeglich waren.
Dachte ich mir doch, dass ich dich falsch verstanden habe.
Du redest von kommerziellem Webspace, aber ich dachte du meinst, dass ich wirklich einen Server mieten soll, das ist ja AFAIK ein Unterschied.
Gut, denn kommerzieller Webspace ist nicht sonderlich teuer, da bekommt man schon guten für 3 Euro im Monat.
Auch komerzieller Webspace hat in der Regel keinen Shellzugriff, den man für Cronjobs braucht.
Events?
Ich hab sie einfach mal so genannt. Wie genau das aussieht, hängt vom Spiel ab. Im simpelsten Fall zum Beispiel eine Tabelle mit Timestamp, User ID, Eventtyp (Gebäude bauen, Einheit bauen, Truppenbewegung) und Parametern (Position, Art der Gebäude / Einheiten)
+---------+------------+--------+------+------------+
| eventid | timestamp | userid | type | parameters |
+---------+------------+--------+------+------------+
| 1 | 1156343703 | 5 | 42 | 423,411,55 |
+---------+------------+--------+------+------------+
type = 42 könnte etwa für Gebäude bauen stehen und die Parameter hießen dann beispielsweise, dass an der Position 423,411 ein Gebäude vom Typ 55 gebaut werden soll.
Wenn der Spieler ein Gebäude in Auftrag gibt, wird einfach so ein Event mit dem Fertigstellungszeitpunkt in die Datenbank geschrieben.
Strings sind .. anders. Da hilft die oben genannte Funktion schon, aber dann muss man immernoch den Inhalt validieren. D.h. bei der Ein- eventuell auch bei der Ausgabe bestimmte Zeichen überprüfen und ggf. ersetzen. Z.B. <script> Bereiche oder javascript: in URIs, je nach Schema eben.
Für die Ausgabe ist da fast immer htmlentities($bla) oder htmlentities(stripslashes($bla)) passend.
Auch komerzieller Webspace hat in der Regel keinen Shellzugriff, den man für Cronjobs braucht.
Ich hab sie einfach mal so genannt. Wie genau das aussieht, hängt vom Spiel ab. Im simpelsten Fall zum Beispiel eine Tabelle mit Timestamp, User ID, Eventtyp (Gebäude bauen, Einheit bauen, Truppenbewegung) und Parametern (Position, Art der Gebäude / Einheiten)
+---------+------------+--------+------+------------+
| eventid | timestamp | userid | type | parameters |
+---------+------------+--------+------+------------+
| 1 | 1156343703 | 5 | 42 | 423,411,55 |
+---------+------------+--------+------+------------+
type = 42 könnte etwa für Gebäude bauen stehen und die Parameter hießen dann beispielsweise, dass an der Position 423,411 ein Gebäude vom Typ 55 gebaut werden soll.
Wenn der Spieler ein Gebäude in Auftrag gibt, wird einfach so ein Event mit dem Fertigstellungszeitpunkt in die Datenbank geschrieben.
Für die Ausgabe ist da fast immer htmlentities($bla) oder htmlentities(stripslashes($bla)) passend.
Achso, jetzt habe ich in etwa das Grobprinzip der Rohstoffberechnung (bzw der zeitgesteurten Scripts) verstanden.
Es wird gar kein Script in einer bestimmten Zeit ausgeführt, das dem Benutzer eine bestimmte Anzahl von Rohstoffen produziert, sondern der Benutzer ruft das Script quasi selbst auf.
Das heißt, er erhält die Rohstoffe eigentlich nur dann, wenn er das Script indirekt aufruft, würde er sich nicht einloggen, so würde er nach der vorgeschriebenen Zeit die Rohstoffe auch gar nicht bekommen. (bzw die Datenbankwerte würden sich nicht ändern)
Versteh ich das richtig?
Für die Ausgabe ist da fast immer htmlentities($bla) oder htmlentities(stripslashes($bla)) passend.
Das ist klar, das andere ist viel wichtiger. Manche Browser lassen z.B. javascript:URIs im <img /> Element zu. Wenn man da nicht aufpasst ist schnell was passiert.
Eine Frage hätte ich noch:
Wie macht es Ogame beispielweise, dass man immer wieder auf die Hauptseite (www.ogame.de) kommt, sobald man eine Url kopiert, im Browser einfügt und absendet?
Da gibts zwei Möglichkeiten:
Du überprüfst serverseitig den Referrer der Seite, d.h. wenn keiner vorhanden -> Weiterleitung zur Startseite.
Clientseitig per JavaScript. Hier müsstest du vermutlich auch irgendwie den Referrer auslesen und dann die Seite umleiten können.
Hm, das heißt ja dann, dass man sämtliche Informationen problemlos per GET übergeben könnte, denn der User besitzt keine Möglichkeit sie zu ändern.
Jesus_666
17.12.2006, 17:08
Oder so:
1.) Ist eine Session-ID angegeben?
Wenn nein -> Startseite
2.) Gibt es im Server eine aktuelle Session, die der ID entspricht?
Wenn nein -> Startseite
3.) Gehört diese Session auch der IP, die sich gerade meldet?
Wenn nein -> Startseite
Ich mache selten Sessionmanagement; IIRC erledigt PHP diese Arbeit schon und man muß im Wesentlichen fragen, ob es aktuell eine gültige Session gibt oder nicht.
Hm, das heißt ja dann, dass man sämtliche Informationen problemlos per GET übergeben könnte, denn der User besitzt keine Möglichkeit sie zu ändern.
Problemlos bestimmt nicht. Formulardaten können z.B. noch immer beliebigen Inhalt haben.
Ich bin mir nicht sicher, ob das folgende auch auf Webseiten im Cache zutrifft. Aber es gibt Möglichkeiten Webseiten die gerade Angezeigt werden zu bearbeiten. Die Seite wäre dann theorethisch zwar nur im Cache manipuliert, der Inhalt wird aber ohne weiteres an dich gesendet.
Nochmal: nichts, aber auch absolut gar nichts, was vom User gesendet wird, ist vertrauenswuerdig. Man kann ohne Probleme jeden HTTP-Header, den man sendet (GET- und POST-Infos, Cookies, Referrer, alles) manipulieren. Wenn du dich nicht auf User, die exakt das tun, vorbereitest, kannst du damit ganz boese auf die Schnauze fliegen.
Oder so:
1.) Ist eine Session-ID angegeben?
Wenn nein -> Startseite
2.) Gibt es im Server eine aktuelle Session, die der ID entspricht?
Wenn nein -> Startseite
3.) Gehört diese Session auch der IP, die sich gerade meldet?
Wenn nein -> Startseite
Ich mache selten Sessionmanagement; IIRC erledigt PHP diese Arbeit schon und man muß im Wesentlichen fragen, ob es aktuell eine gültige Session gibt oder nicht.
Hm, nein das ist bei Ogame anders, denn du bist selbst derjenige, der diesen Link eingibt.
Anstatt auf "gebaude.php?sesid=jdsjdkjadjsdiafj&build=2" zu klicken kopiert man einfach den Link und fügt ihn selbst im Browser ein und trotzdem kommt man zurück auf die Startseite.
Jesus_666
17.12.2006, 20:30
Hm, nein das ist bei Ogame anders, denn du bist selbst derjenige, der diesen Link eingibt.
Anstatt auf "gebaude.php?sesid=jdsjdkjadjsdiafj&build=2" zu klicken kopiert man einfach den Link und fügt ihn selbst im Browser ein und trotzdem kommt man zurück auf die Startseite.
Dann wird da vermutlich irgendwo ein JavaScript-Skript drinstecken.
Kleine Ergaenzung am Rande: einige Leute uebersehen gerne, dass Cookies auch User-Input sind. Ich hab schon mehr als einmal 'ne Webanwendung gesehen, die zwar GET- und POST-Parameter filtert, bei der aber SQL-Injections ueber manipulierte Cookies moeglich waren.
Dito. ich hab mir auch schonmal eine Injection selbstgemacht, indem ich $_SERVER['REQUEST_URI'] in eine MySQL Abfrage gepackt habe, ohne zu escapen.
Nochmal: nichts, aber auch absolut gar nichts, was vom User gesendet wird, ist vertrauenswuerdig. Man kann ohne Probleme jeden HTTP-Header, den man sendet (GET- und POST-Infos, Cookies, Referrer, alles) manipulieren. Wenn du dich nicht auf User, die exakt das tun, vorbereitest, kannst du damit ganz boese auf die Schnauze fliegen.
Nochmal dito *spam*
3.) Gehört diese Session auch der IP, die sich gerade meldet?
Das ist teilweise problematisch, weil die Leute dann nach einem erneuten Verbindungsaufbau sich nicht mehr einloggen können, weil sie dann wahrscheinlich eine neue IP haben. Das ist bei Browsergames zwar nicht so wichtig, aber das sollte man imo bedenken.
Das ist teilweise problematisch, weil die Leute dann nach einem erneuten Verbindungsaufbau sich nicht mehr einloggen können, weil sie dann wahrscheinlich eine neue IP haben. Das ist bei Browsergames zwar nicht so wichtig, aber das sollte man imo bedenken.
Wobei man hier zwei Fälle unterscheiden muss!
Wird die SID in der URI mitgegeben? Dann muss eine IP Prüfung gemacht werden!
Wird die SID per Cookie übergeben? Dann sollte eventuell der Browser überprüft werden.
Aber natürlich müssen in Cookies noch andere Angaben vorhanden sein, damit man den Benutzer eindeutig identifizieren kann.
Wobei man hier zwei Fälle unterscheiden muss!
Wird die SID in der URI mitgegeben? Dann muss eine IP Prüfung gemacht werden!
Wird die SID per Cookie übergeben? Dann sollte eventuell der Browser überprüft werden.
Aber natürlich müssen in Cookies noch andere Angaben vorhanden sein, damit man den Benutzer eindeutig identifizieren kann.
Deinen Punkt 2. versteh ich nicht wirklich. Inwiefern willst du den Browser überprüfen?
Deinen Punkt 2. versteh ich nicht wirklich. Inwiefern willst du den Browser überprüfen?
Serverseitig. Will sagen: Verwendet der Spieler noch immer den selben Browser? Wenn es da zu einem Browserunterschied kommt, ist es wahrscheinlich, dass der Cookie geklaut wurde, weshalb der Zugang nicht gewährt werden sollte.
Machen auch manche Forensoftware so, obwohl sich das auch ausschalten lässt.
Man kann Cookies auch manipulieren, ohne den Browser zu wechseln. Demnach ist die Überprüfung ziemlich schwachsinnig. Und zuverlässig ist sie schon zweimal nicht, weil man als Browserinfo so ziemlich alles senden kann.
Man kann Cookies auch manipulieren, ohne den Browser zu wechseln.
Ja, du denkst da aber an einen anderen Aspekt als ich.
Demnach ist die Überprüfung ziemlich schwachsinnig.
Denke ich nicht. Wenn jemand sich mit einem falschen Cookie einloggen will, aber zufällig den falschen Browser dazu verwendet, dann ist letzteres die einzige information, die ein Programm verarbeiten könnte. Von daher sollte man davon ausgehen, dass ein Cookie, das beim falschen Browser liegt, getürkt ist.
Und zuverlässig ist sie schon zweimal nicht, weil man als Browserinfo so ziemlich alles senden kann.
Das ist wahr, allerdings: Der Standarduser macht das nicht. Ebensowenig transferiert er Cookies, wenn er nicht gerade von einem Browser zum anderen umsteigt.
Von daher halte ich die Annahme „unterschiedliche Browser -> Hackversuch“, durchaus für gerechtfertigt.
Btw nochmal zum Thema Injections.
Ist es nicht eine einfache und gute Möglichkeit die Usereingabe, bevor sie für den eigentlichen Script verwendet wird, auf Zeichen, wie beispielsweise das Semikolon, oder auf Werte wie "delete" zu überprüfen und diese ggf. aus der Eingabe zu löschen.
Gut, in letzterem Beispiel dürfte kein User das Wort "delete" im Name verwenden, aber was solls.
So wie ich dich verstanden hab, soll das hauptsächlich eine Schutzmaßnahme gegen Bots sein, die sich auf irgendwelchen Rechnern einnisten, deren Cookies auslesen und dann Unsinn anstellen, richtig? Ich frag mich, warum man ein so kleines Browsergame explizit gegen sowas absichern sollte. Die meisten Leute, die das Spiel hacken wollen, haben kein Problem, sich nochmal neu einzuloggen, falls sie überhaupt ein extra Programm verwenden. Allgemein sollte man eher Sicherheitslücken vermeiden als es den Hackern zu erschweren, sie zu nutzen. Erinnert mich grad irgendwie an Microsoft und an die deutsche Politik, so von wegen Airbag einbauen, wenn die Bremse kaputt ist.
@Antares:
Regular Expressions sind dein Freund. Im Programmierforum gabs vor Monaten mal nen sehr schönen Thread von Jeez zu dem Thema. Ich würde aber eher drauf achten, die Befehle sauber zu escapen und in Anführungszeichen zu packen. Folgender Code ist ziemlich ungefährlich:
mysql_query('SELECT * FROM `users` WHERE `username`=\''.addslashes($_GET['username']).'\'');
Da kann der User Anführungszeichen, Semikolons und Delete eingeben, soviel er lustig ist, es wird nichts passieren, außer dass kein Ergebnis gefunden wird. Nur das % sollte man evtl. ausfiltern, wie beispielsweise die Suchfunktion von www.informatikjahr.de zeigt. Einfach mal % eingeben und schaun, was passiert. Die Seite scheint eh kein bisschen gegen Injections geschützt zu sein.
So wie ich dich verstanden hab, soll das hauptsächlich eine Schutzmaßnahme gegen Bots sein, die sich auf irgendwelchen Rechnern einnisten, deren Cookies auslesen und dann Unsinn anstellen, richtig?
Daran hab ich, erhlichgesagt, garnich gedacht, sondern an den klassischen Cookieklau per XSS.
Ich frag mich, warum man ein so kleines Browsergame explizit gegen sowas absichern sollte.
Ich schrieb ja auch eventuell. Ich wusste halt, dass das gemacht wird und brachte es in den Post ein.
Allgemein sollte man eher Sicherheitslücken vermeiden als es den Hackern zu erschweren, sie zu nutzen.
Richtig, aber das täte es ja.
Wenn ich annehme, dass ein Besucher immer mit dem selben Browser kommt, dann nehme ich auch an, dass nur dieser das Cookie besitzen kann. Hat ein anderer das Cookie sage ich nein.
Nehme ich allerdings an, dass ein Cookie von überall kommen kann, dann wird ein Hacker nicht ausgeschlossen, wenn er die selben Cookies wie der echte Spieler hat, aber einen anderen Browser.
Woher soll ein Programm wissen, dass es sich um einen falschen Cookie handelt. Oder wie soll ein Browsergame verhindern, dass ein Bot die Cookies durchstöbert?
XSS sollte der Autor vermeiden, ja. Aber mehr kann er in der Hinsicht wohl nicht tun.
mysql_query('SELECT * FROM `users` WHERE `username`=\''.addslashes($_GET['username']).'\'');
Ja, aber man sollte doch für SQL-Abfragen, immer die entsprechende Escapefunktion verwenden (mysql_real_escape_string()), welche alle Zeichen escaped, die dem String gefährlich werden könnten.
Außerdem würde ich hier die unnötige maskierung vermeiden. Mich bringt sowas immer durcheinander.
mysql_query('SELECT * FROM `users` WHERE `username`="' . mysql_real_escape_string($_GET['username']) . '";');
Jesus_666
18.12.2006, 09:20
BTW, falls man Zugriff auf PHP 5.1 oder höher hat kann man auch PDO (http://de2.php.net/pdo) verwenden. Mit PDO hat man nicht nur auto-escapte Variablen (Achtung, % und _ werden AFAIK immer noch nicht gefiltert) sondern auch Zugriff auf erweiterte Funktionalität wie Transaktionen, die, sobald man sich etwas mit ihnen beschäftigt hat, sehr nützlich sein können.
Welches Anzeigesystem benutzt man denn hauptsächlich bei Browsergames?
Frames?
Include? (?content=)
Oder doch diese ominösen Templates?
Kann man alles, muss man gar nichts. Wobei Templates schon geschickt waeren (wie bei jeder Art von Website).
Jesus_666
20.12.2006, 10:57
Zumal Templates keine Alternative zu Frames und Includes sind - Templates bauen auf Includes auf und können mit Frames kombiniert werden.
Templates funktionieren ganz grob so:
1.) Du lädst das Template in eine Variable.
$template = file_get_contents('templates/omgsupertemplate.htm');
2.) Das Template enthält Platzhalter, die du durch konkrete Werte ersetzt.
$template = str_replace('%sinndeslebens%', 'Brot essen', $template);
$template = str_replace('%fontsize%', $variable, $template);
3.) Nachdem du alle Ersetzungen durchgeführt hast machst du, was auch immer du mit dem Output tun willst.
echo $template;
Zur Veranschaulichung hier noch mal ein Vorher-Nachher-Vergleich. ($variable == 42)
VORHER
<html>
<body>
<div style="font-size: %fontsize%">
Der Sinn des Lebens ist: %sinndeslebens%.
</div>
</body>
</html>
NACHHER
<html>
<body>
<div style="font-size: 42">
Der Sinn des Lebens ist: Brot essen.
</div>
</body>
</html>
Templates sind ziemlich mächtig und erlauben es dir, PHP- und HTML-Code sauber zu trennen, was die Wartbarkeit der Seite beträchtlich erhöhen kann. Du kannst auch problemlos Templates ineinander verschachteln (wie das geht sollte offensichtlich sein) und so auch komplexe Layouts hinkriegen.
Edit:
Ich wurde darauf hingewiesen, daß es nicht offensichtlich ist. Hier also noch mal genau:
Wenn du dein Template abgearbeitet hast, also mit Schritt 2 durch bist, hast du den ganzen Kram in einer Variable. Die kannst du nun wiederum ganz normal in ein anderes Template einfügen. Und schon hast du den Kram verschachtelt. Du muß nur eben darauf achten, daß du alles, was in einem Untertemplate abgearbeitet wird, in einer eigenen Templatedatei ablegst.
Manni hat da eine sehr gute Klasse geschrieben, die die Arbeit mit Templates ziemlich einfach macht. Vielleicht ist er ja so nett und veröffentlicht die mal.
@Jeez:
Also, im Grunde habe ich das System verstanden, doch bleiben noch ein paar Fragen offen:
Das Includesystem (mit Content) ist ja recht einleuchtend.
Ich schreibe "?content=start"
Und an der jeweiligen Stelle "if($content=="start") { include...."
Bzw ich benutze einen Switch.
Allerdings werden die verschiedenen Seiten bei Templates meineswissens nicht per Variable angesteuert.
Also anstatt "www.blah.de/index.php?content=start" steht dann dort "www.blah.de/start.php"
Und jetzt verstehe ich nicht, wie ich ein solches System mit Templates aufbauen muss.
Jesus_666
20.12.2006, 17:46
Zuerst mal natürlich if ($_REQUEST['content'] === 'start'). $content ist nur dann direkt verfügbar, wenn du dir Autoglobals erzeugen läßt - und das ist erstens nicht auf allen Servern eingerichtet und zweitens kann es zu Sicherheitslücken führen, wenn man nicht aufpaßt.
Falls du dir $content aus dem Userinput selbst erzeugt hast ist die Stelle natürlich in Ordnung.
Von deinem System auf meins umzusatteln ist gar nicht so schwer - immerhin funktionieren beide dadurch, daß an der entsprechenden Stelle die Templates geladen werden. Anstatt einfach die Datei zu inkludieren lädst du sie in eine Variable und fügst die in das Haupttemplate ein, das du am Ende ausgibst.
Mein System basiert ja darauf, daß du keinen Output hast, den du nicht explizit anforderst (dadurch, daß du ein echo $bla; machst). Du lädst also erst die Grundseite als Template und fügst dann dort alle weiteren Teile ein. Um also eine andere Seite zu "inkludieren" setzt du einfach an der entsprechenden Stelle in der Grundseite einen Platzhalter und packst da per str_replace() die geladene Seite rein.
BTW, was meinst du mit "werden bei Templates nicht per Variable angesteuert"? Templates sind völlig unabhängig davon, wie man den Inputverarbeitet - und sowohl das, was ich mache als auch das, was du da beschreibst sind Templates; meine sind nur abstrakter gehalten.
@Jeez:
Nunja, was ich mit ansteuern meinte:
Klickt ein User auf den Link "?content=start", so sagt er ja dem Server, dass die Variable Content den Wert "start" annimmt.
Jetzt handelt der Server, beispielsweise nach dem if-Schema, also "wenn die Variable Contetnt den Wert "start" annimmt, dann inkludiert er die start.php an die entsprechende Stelle.
Also steuert man die verschiedenen Inhalte an, indem man per Klick auf einen Link die Variable Content ändert, und der Server demntsprechend reagiert.
Achja und Autoglobals?
Damit arbeite ich gar nicht.
Ich hole mir den Wert von Content einfach mit GET.
Also $content=$_GET["content"];
So und wenn ich ohne dieses System arbeiten würde, so würde ich ganz einfach den Link auf "start.php" setzen.
Allerdings müsste ich auf diese Weise sämtliche Strukturen implementieren.
Also jede einzelne Datei per HTML ein Menü, einen Header, einen Footer, etc. einbringen - und diese Methode ist definitiv zu arbeitsaufwändig, vorallem, wenn sich das Menü mal ändern sollte.
In diesem Fall müsste man Änderungen in sämtlichen Dateien vornehmen.
Und ich dachte mir eben, dass diese letzte Variante eben mit Templates funktionieren würde.
Leider fehlt mir da momentan noch der Durchblick.
Um die Sache verständlicher zu machen ein kleines Beispiel:
Da wäre die Datei "/inhalt/omgrofl.html"
Eine weitere Datei wäre die normale "inhalt/lamor.html"
Index.php
<table>
<td>
Menu
<br />
<a href="/inhalt/omgrofl.html">Rofl</a>
</td>
<td>
Standard --> lamor.html
</td>
</table>
Wie man sieht sollen Standardmäßig die Inhalte der "lamor.html" zu sehen sein.
So, meine Frage hierzu:
Wie muss der PHP Code der index.php aussehen, und wie der Inhalt der "lamor.html" und der "omgrofl.html" ?
Seiten, die ihren Inhalt auf Dateien mit *.php verteilen arbeiten ebenso mit Inkludierung.
Statt dem Inhalt wird eben das Grundgerüst drum herum inkludiert.
<?php
include ( 'HTMLKopf.php' );
// Inhalt
include ( 'HTMLFuss.php' );
?>
Achja und Autoglobals?
Damit arbeite ich gar nicht.
Ich hole mir den Wert von Content einfach mit GET.
Also $content=$_GET["content"];
$_GET ist eine Autoglobale, warum nicht direkt damit arbeiten?
Jesus_666
20.12.2006, 18:57
Okay, hier mal ein kleines Beispiel. Ich verwende hier meine eigenen Kontentionen; beispielsweise steht die Dateiendung .hic für HTML-Includes.
<?php
// Das Grundgerüst der Seite.
$template = file_get_contents('res/base.hic');
switch ($_REQUEST['target'])
{
case 'contact':
$body = file_get_contents('res/contact.inc');
break;
case 'about':
$body = file_get_contents('res/about.inc');
$body = str_replace('{time}', date('H:i:s'), $body);
break;
case 'home':
default:
$body = file_get_contents('res/home.inc');
}
$template = str_replace('{body}', $body, $template);
?>
[res/base.inc]
<html>
<head>
<title>{title}</title>
</head>
<body>
<div><img src="src/banner.png" alt="Tollsoft ist toll!"></div>
<div>
{body}
</div>
<div>
Dieser Footer ist (c)2014, Tollsoft.<br>
Best viewed with NCSA Mosaic at 640x480.
</div>
</body>
</html>
[res/about.inc]
<h1>Die Firma Tollsoft</h1><br>
Die Firma Tollsoft wurde gegründet, um tolle Sachen zu machen.<br>
Wir produzieren auch Uhrzeiten, so wie diese: {time}
Komplexere Sachen löse ich dadurch, daß ich sie in einer separaten PHP-Datei behandle und die bei Bedarf inkludiere.
Zum Thema index.php?content=start vs. start.php:
Ob du jetzt in der index.php ne Abfrage machst, ob $content === "start" oder ob du in der start.php einfach nur den Kram hast, der nach der Abfrage ausgeführt würde, kommt ja dann aufs gleiche raus.
Mit Jeez' Variante könnte man etwa so verfahren:
contact.php
<?php
$template = file_get_contents('res/base.hic');
$body = file_get_contents('res/contact.inc');
$template = str_replace('{body}', $body, $template);
?>
about.php
<?php
$template = file_get_contents('res/base.hic');
$body = file_get_contents('res/about.inc');
$body = str_replace('{time}', date('H:i:s'), $body);
$template = str_replace('{body}', $body, $template);
?>
Das hat zwar den Nachteil, dass ein paar Zeilen doppelt sind, aber dafür hat man ordentliche Links.
Übrigens noch ein kleines Beispiel, wie das mit Mannis Klasse aussehen könnte:
start.tpl (Endung kann natürlich auch anders sein)
<html>
<head>
<title>{title}</title>
</head>
<body>
<INCLUDE! navigation.tpl>
<div>{text}</div>
</body>
</html>
navigation.tpl
<ul>
<BLOCK! navigation>
<li><a href="{navigation.href}">{navigation.name}</a></li>
</BLOCK!>
</ul>
start.php
<?php
include "template.class.php";
include "setup_template.php";
include "navigation.php";
$template->set_variable(array("title" => "Start", "text" => "Lorem Ipsum"));
$template->parse("start");
?>
setup_template.php
<?php
$template = new Template('templates/', 'templates/cached/');
$templatedir = dir($template->path);
while(($filename = $templatedir->read()) !== false)
{
if(preg_match('#^(.*?)\.tpl$#i', $filename, $m))
{
$templates[$m[1]] = $filename;
}
}
$template->setfile($templates);
?>
navigation.php
<?php
$navigation = array();
$navigation[] = array("href" => "start.php", "name" => "Start");
$navigation[] = array("href" => "downloads.php", "name" => "Downloads");
$template->set_block_variable("navigation", $navigation);
?>
Dazu drei Anmerkungen:
Es sieht mit den vielen Dateien ziemlich umständlich aus, aber davon muss man pro Seite nur zwei (z.B. start.tpl und start.php) schreiben
Die setup_template.php kann man sich sparen, indem man nur die Templates lädt, die man braucht, aber ich lass aus Bequemlichkeit immer alle laden, die sich im entsprechenden Verzeichnis befinden.
Mannis Klasse erlaubt foreach-Schleifen (<BLOCK!>), Bedingungen (<IF!>, <ELSE!>) und Includes (<INCLUDE!>) und ist damit sehr flexibel.
@DFYX & Jeez:
Danke für die Tutorials !
Ich wollte gerne mal eine Injection testen.
Also hab ich mir nen Code zusammengebastelt.
Leider funktioniert das nicht...
test.php
<?php
$verbindung = mysql_connect ("...",
"...", "...")
or die ("keine Verbindung möglich.
Benutzername oder Passwort sind falsch");
mysql_select_db("usr_web455_4")
or die ("Die Datenbank existiert nicht.");
//Dateien ausgeben
$id=$_GET["id"];
$abfrage = "SELECT * FROM test WHERE id='$id'";
$ergebnis = mysql_query($abfrage);
?>
form.php
<form action="test.php" method="GET">
<input type="text" name="id"><br />
<input type="submit" value="Submit">
</form>
Ins Input schreibe ich 1'"; $abfrage="DELETE FROM test"; //
Trotzdem funktioniert es nicht...
Ins Input schreibe ich 1'"; $abfrage="DELETE FROM test"; //
Das wäre auch ein PHP Skript,d as du da absendest, so geht das nicht! Die Injection geschieht ja innerhalb einer Zeichenkette, die als Query asgeführt wird.
$abfrage = "SELECT * FROM test WHERE id='$id'";
Eine Injection müsste so aussehen: 1'; DELETE FROM `test` WHERE '1'='1
Damit lautet die Abfrage:
$abfrage = "SELECT * FROM test WHERE id='1'; DELETE FROM `test` WHERE '1'='1'";
Womit du zwei funktionsfähige Queries hast.
PHP lässt es aber nicht ganz so einfach zu:
Magic Quotes escapen einige Sonderzeichen. Diese Einstellung ist sehr oft aktiviert, fällt aber in der nächsten Version von PHP weg. Dann ist die Einstellung unveränderlich deaktiviert, d.h. keine maskierung mehr.
MySQL-Sicherheitsmechanismus: Nur eine Abfrage kann innerhalb von mysql_query() ausgeführt werden. Wiege dich da aber nicht in Sicherheit, das ist kein Schutz. Vor allem wenn die Magic Quotes bald deaktiviert werden.
Jesus_666
25.12.2006, 01:29
MySQL-Sicherheitsmechanismus: Nur eine Abfrage kann innerhalb von mysql_query() ausgeführt werden. Wiege dich da aber nicht in Sicherheit, das ist kein Schutz. Vor allem wenn die Magic Quotes bald deaktiviert werden.
Yup. Man kann nämlich auch aus zwei Abfragen einfach eine Abfrage mit zwei Unterabfragen machen. SQL ist ziemlich mächtig.
@mitaki:
Ehrlich gesagt hab ichs mit deiner Methode auch schon versucht, allerings ohne WHERE bei DELETE.
Hat mich zu keinem Erfolg geführt, und deshalb habe ich die Variante mit dem PHP Script versucht.
Hing vllt an den von dir erwähnten Sicherheitsmaßnahmen.
*Edit*
Nein, so funktioniert es nicht.
Selbst dann nicht, wenn ich den Code per Hand ins Script schreibe.
$abfrage = "SELECT * FROM test WHERE id='1'; DELETE FROM `test` WHERE '1'='1'";
Powered by vBulletin® Version 4.2.3 Copyright ©2025 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.