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
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.
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, 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:
Zitat von Antares
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.
Zitat
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.
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.
Zitat von Antares
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)
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.
Zitat von mitaki
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)
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.
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.
Zitat von mq
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*
Zitat
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.
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?