[PHP + MySQL] Detailfragen zu Online-Highscore-Listen

Design Patterns, Erklärungen zu Algorithmen, Optimierung, Softwarearchitektur
Forumsregeln
Wenn das Problem mit einer Programmiersprache direkt zusammenhängt, bitte HIER posten.
Antworten
Benutzeravatar
Schrompf
Moderator
Beiträge: 4855
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

[PHP + MySQL] Detailfragen zu Online-Highscore-Listen

Beitrag von Schrompf »

Hallo Leute!

Heute geht es mal um PHP und MySQL - ungewohnte Themen hier, aber hier gibt es doch ne Menge schlauer Köpfe, so dass ich doch Hoffnung habe, meine Anfänger-Fragen beantwortet zu bekommen.

Ich baue gerade an einem Framework für Online Hiscores. Ursprünglich hat Joggel das Projekt gegründet, und ich baue es jetzt fertig. Wenn es dann fertig ist, soll das Framework als OpenSource veröffentlicht werden, damit jeder was davon hat.

Das Framework besteht aus einem C++-Teil - libCurl plus ein paar eigene Klassen - und einem Online-Teil - ein paar PHP-Skripte zum Einrichten der Datenbank, zum Hinzufügen neuer Einträge und zur Abfrage nach verschiedenen Kriterien. Und beim Online-Teil brauche ich eure Hilfe, da ich bei PHP und MySQL noch sehr neu bin.

Problem A - Abfrage der Listen

Die besten 20 oder so ist kein Problem. Die Abfrage lautet aktuell so: "SELECT * FROM $tableName ORDER BY score DESC LIMIT $entryCount" Soweit, so gut. Aber es interessiert keinen Spieler, wie weit er von Platz eins weg ist, weil auf Platz1 irgendne kranke Sau ohne RL hockt. Es interessiert dagegen, wie man relativ zu seinen Freunden steht und auf welchem Platz die gerade absolvierte Runde rausgekommen ist. Ich will also die Liste nach Namen filtern. Und da fängt das Problem an: es gibt keine expliziten Plätze.

Ich könnte einfach eine WHERE-klausel einbauen. Aber dann kenne ich nicht die wirklichen Platzierungen der Leute, die ich zurückbekomme, sondern nur ihre relative Position zueinander. Wie komme ich an richtige Platzierungen? Ich stelle mir das so vor, die Tabelle nach jedem Eintrag irgendwie zu sortieren und in jeden Datensatz die Platzierung zu schreiben. Aber wie mache ich das? Ein paar Stichworte, nach denen ich googeln soll, würden mir schon reichen.

Problem B - Verifikation der Einträge

Aktuell kann jeder, der URL und Parameter kennt, neue Einträge in die Hiscore-Liste seiner Wahl eintragen. Das ist jetzt noch ok, aber nicht auf Dauer. Wie sichere ich Einträge so ab, dass ich halbwegs sicher gehen kann, dass sie von dem Spiel kommen, das Einträge schreiben darf?

Ich habe mir dazu überlegt, eine Signatur an jeden Request anzuhängen. Also sowas wie "putentry.php?table=rattatt&name=Bla&score=12345&sig=a6glPv2y4". Ich habe mir jetzt überlegt, auf Seiten des Spiels einen String "rattattBla12345" zusammenbauen und mit einem Private Key verschlüsseln, der im Spiel hinterlegt ist. Das PHP-Skript könnte ihn dann mit dem dazugehörigen Public Key wieder entschlüsseln und testen, ob der Eintrag valide ist. Kann das so funktionieren? Gibt es dafür fertige Funktionen für Verschlüsseln und Entschlüsseln auf C++-Seite und PHP-Seite?

Problem C - saubere Übertragung der Parameter

Außerdem habe ich noch das Problem, dass der Name des Spielers potentiell irgendwelche absonderlichen Zeichen enthalten könne. Gibt es eine Standard-Methode, Strings zu encoden, so dass sie weder als Teil der URL noch im SQL-Kommando Probleme machen? Ich möchte gern vermeiden, dass ein Schlaubürger bei Splatter ein Spielerprofil namens "Theo'; DROP TABLE" anlegt und damit die Datenbank rösten kann.

Danke!
Zuletzt geändert von Chromanoid am 16.11.2012, 19:23, insgesamt 2-mal geändert.
Grund: Joggel's Namen entfernt
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
eXile
Establishment
Beiträge: 1136
Registriert: 28.02.2009, 13:27

Re: [PHP + MySQL] Detailfragen zu Online-Highscore-Listen

Beitrag von eXile »

Schrompf hat geschrieben:Problem B - Verifikation der Einträge

Ich habe mir dazu überlegt, eine Signatur an jeden Request anzuhängen. Also sowas wie "putentry.php?table=rattatt&name=Bla&score=12345&sig=a6glPv2y4". Ich habe mir jetzt überlegt, auf Seiten des Spiels einen String "rattattBla12345" zusammenbauen und mit einem Private Key verschlüsseln, der im Spiel hinterlegt ist. Das PHP-Skript könnte ihn dann mit dem dazugehörigen Public Key wieder entschlüsseln und testen, ob der Eintrag valide ist. Kann das so funktionieren? Gibt es dafür fertige Funktionen für Verschlüsseln und Entschlüsseln auf C++-Seite und PHP-Seite?
Da hast du das gleiche Problem wie bei einem Kopierschutz: Prinzipiell ist ja der Spieler erlaubt, jeden beliebigen Wert in die Highscore-Liste zu schreiben; er kann eben jeden solchen Wert im Spiel erreichen. Was du willst, ist eine Beschränkung der Client-Programme, die deine Seite benutzen dürfen: Nämlich nur authentifizierte Client-Programme.

Du kannst jetzt so Placebo-Dinge einführen wie Passwörter, Public-/Private-Key-Verschlüsselung, etc. Aber meiner ersten Einschätzung nach dürfte das prinzipiell nichts ändern: Das Programm hält immer das Passwort bzw. den Private-Key vor; damit ist der Benutzer immer im besitzt des Authentifizierungsmerkmals und somit zugangsberechtigt. Genau wie bei einem Kopierschutz.

Die korrekte Lösung wäre wohl, den gesamten Spielverlauf aufzuzeichnen und auf Plausibilität (was auch immer das ist) zu testen. Was wohl unpraktikabel ist.
Schrompf hat geschrieben:Problem C - saubere Übertragung der Parameter

Außerdem habe ich noch das Problem, dass der Name des Spielers potentiell irgendwelche absonderlichen Zeichen enthalten könne. Gibt es eine Standard-Methode, Strings zu encoden, so dass sie weder als Teil der URL noch im SQL-Kommando Probleme machen? Ich möchte gern vermeiden, dass ein Schlaubürger bei Splatter ein Spielerprofil namens "Theo'; DROP TABLE" anlegt und damit die Datenbank rösten kann.
Benutze parametrisierte SQL-Queries. Manuell SQL-Query-Strings zusammenbasteln ist sowas von letzte Dekade. ;)

Disclaimer: Ich habe von so etwas, das meilenweit von der Computergraphik wegliegt, keine Ahnung; bitte korrigiert mich.
Benutzeravatar
Schrompf
Moderator
Beiträge: 4855
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: [PHP + MySQL] Detailfragen zu Online-Highscore-Listen

Beitrag von Schrompf »

eXile hat geschrieben:Da hast du das gleiche Problem wie bei einem Kopierschutz: Prinzipiell ist ja der Spieler erlaubt, jeden beliebigen Wert in die Highscore-Liste zu schreiben; er kann eben jeden solchen Wert im Spiel erreichen. Was du willst, ist eine Beschränkung der Client-Programme, die deine Seite benutzen dürfen: Nämlich nur authentifizierte Client-Programme.
Korrekt. Und das ist nicht weiter dramatisch, ich will hier ja keinen Kopierschutz schreiben. Ich will aber verhindern, dass jemand mit Kenntnis der URL eigene Einträge erzeugen kann. Und das sollte mit einer solchen Signierung machbar sein. Dann müsste der Angreifer zumindest an den im Programm abgelegten Private Key rankommen, was schon bei minimaler Code-Anstrengung in einen Disassembler-Marathon ausartet. Das ist immernoch schaffbar, aber eine für meine Zwecke ausreichende Hemmschwelle.

Die Frage lautete daher auch: funktioniert das so? Und wonach muss ich googeln, wenn ich Ver- und Entschlüsselung in C++ und PHP einbauen will?
exile hat geschrieben:Benutze parametrisierte SQL-Queries. Manuell SQL-Query-Strings zusammenbasteln ist sowas von letzte Dekade. ;)
[/quote] Danke, ich werde mal danach suchen.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
waigie
Beiträge: 82
Registriert: 20.05.2009, 19:37

Re: [PHP + MySQL] Detailfragen zu Online-Highscore-Listen

Beitrag von waigie »

Problem A

Code: Alles auswählen

SET @i = 0;
SELECT *, @i = @i +1 AS position FROM $tableName ORDER BY score DESC
Und dann deine Anfragen auf das Result anwenden.

Problem B
PHP kann mit openssl Unterstützung kompiliert werden. Ob das bei dir der Fall ist kann du mittels phpinfo() herausfinden. Wenn ja hast du openssl_open und openssl_seal zur Verfügung. Wie das ganze in C++ geht, kann ich dir jedoch nicht sagen.

Problem C
Wie schon von Exile gesagt. Prepared Statements helfen um die Queries sicher zu gestalten. Um Sonderzeichen URL fähig zu codieren gibt es einen Verfahren. Ich weiß grade nicht mehr genau wie das ging, aber hier http://www.user-archiv.de/url-escape-sequenzen.html gibts ne Liste mit den wichtigsten
Benutzeravatar
eXile
Establishment
Beiträge: 1136
Registriert: 28.02.2009, 13:27

Re: [PHP + MySQL] Detailfragen zu Online-Highscore-Listen

Beitrag von eXile »

Schrompf hat geschrieben:Problem A - Abfrage der Listen

Die besten 20 oder so ist kein Problem. Die Abfrage lautet aktuell so: "SELECT * FROM $tableName ORDER BY score DESC LIMIT $entryCount" Soweit, so gut. Aber es interessiert keinen Spieler, wie weit er von Platz eins weg ist, weil auf Platz1 irgendne kranke Sau ohne RL hockt. Es interessiert dagegen, wie man relativ zu seinen Freunden steht und auf welchem Platz die gerade absolvierte Runde rausgekommen ist. Ich will also die Liste nach Namen filtern. Und da fängt das Problem an: es gibt keine expliziten Plätze.

Ich könnte einfach eine WHERE-klausel einbauen. Aber dann kenne ich nicht die wirklichen Platzierungen der Leute, die ich zurückbekomme, sondern nur ihre relative Position zueinander. Wie komme ich an richtige Platzierungen? Ich stelle mir das so vor, die Tabelle nach jedem Eintrag irgendwie zu sortieren und in jeden Datensatz die Platzierung zu schreiben. Aber wie mache ich das? Ein paar Stichworte, nach denen ich googeln soll, würden mir schon reichen.
Ich habe mir da eine ähnliche Sache wie mein Vorredner einfallen lassen:

Code: Alles auswählen

SELECT Rank, Highscore.Name, Score
FROM Highscore

INNER JOIN

(SELECT @i:=@i+1 AS Rank, Name
FROM Highscore, (SELECT @i:=0) AS Iterator
ORDER BY Score DESC) AS Ranks

ON Highscore.Name = Ranks.Name

WHERE Highscore.Name IN ("friend1", "friend8", "friend7");
Für sichere, parametrisierte SQL-Queries mit IN-Bezeichner, siehe bitte hier.

Mögliche Probleme, die ich nicht abschätzen kann, sind:
  1. Wie standard-konform der Code da oben ist (gibt es überhaupt ein Konzept der Reihe in SQL?)
  2. Wie du die Benutzernamen abspeicherst. Wenn es mehrere Benutzer mit gleichen Namen geben kann, frickel das Teil oben halt auf Benutzer-IDs um.
waigie hat geschrieben:PHP kann mit openssl Unterstützung kompiliert werden. Ob das bei dir der Fall ist kann du mittels phpinfo() herausfinden. Wenn ja hast du openssl_open und openssl_seal zur Verfügung. Wie das ganze in C++ geht, kann ich dir jedoch nicht sagen.
Meiner Meinung nach tangiert das nur den Schutz vor dem Mitschneiden durch dritte Parteien und Authentizität der Daten, aber nicht die Integrität der Daten (d.h. keine ausgedachten Werte). (Die englischen Namen confidentiality, authenticity, integrity und availability stammen aus der Nomenklatur der IT-Sicherheit; das sind nicht meine Erfindungen. Ich mag die Namen nicht.) Ach so ein Quatsch, ich sollte erst mal die Links durchlesen. Das kann man ja für beliebige Daten einsetzten, und nicht um eine SSL-Verbindung aufzubauen. Entschuldigung. :oops:
Lustige Dinge, die ich gefunden habe und nicht kannte, da ich mich seit Jahren nicht mehr mit so etwas auseinandergesetzt habe:
joggel

Re: [PHP + MySQL] Detailfragen zu Online-Highscore-Listen

Beitrag von joggel »

Bis zum genauen spezifizieren der Anforderung sind wir beide ja nie gekommen... deswegen das (sehr grobe) Codegerüst... ;)
Und ich glaube es wird sehr schwer ein Framework zu entwerfen, dass man für viele Highscore-Systeme, ohne große anpassung, verwenden kann...
Schrompf hat geschrieben:Ich möchte gern vermeiden, dass ein Schlaubürger bei Splatter ein Spielerprofil namens "Theo'; DROP TABLE" anlegt und damit die Datenbank rösten kann.
Was mir damals dazu eingefallen ist:
Auf der Serverseite eine Liste mit verbotenen Parameter halten, und diese, bevor die SQL-Abfrage gebaut wird, mit den in der URL enhaltenen Parametern vergleichen... und entsprechend reagieren.
Notfalls mit einer Ausgabe, dass das ein nicht gültiger Parameter ist oder so...

Zwecks verschlüsselung:
Ich glaube, cUrl kam da mit einer OpenSSL-Option...

Um Sonderzeichen URL fähig zu codieren:
http://curl.haxx.se/libcurl/c/curl_easy_escape.html

My 2 cent..
Zuletzt geändert von joggel am 16.11.2012, 19:58, insgesamt 5-mal geändert.
Benutzeravatar
Chromanoid
Moderator
Beiträge: 4256
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: [PHP + MySQL] Detailfragen zu Online-Highscore-Listen

Beitrag von Chromanoid »

Du könntest Dir mal https://developer.gree.net/en/ oder http://www.scoreloop.com anschauen. Es gibt sicher noch zig andere solcher Anbieter. Bevor man sich da die Finger schmutzig macht, ist das vielleicht mal einen Blick wert, auch wenn es nur der Inspiration dient.
joggel

Re: [PHP + MySQL] Detailfragen zu Online-Highscore-Listen

Beitrag von joggel »

btw:
wäre einer der zuständigen so nett, meinen Namen aus Schrompfs Post zu löschen... Ist ja immerhin noch meine Entscheidung, ob ich meinen Namen ins Forum stelle!!
Benutzeravatar
Chromanoid
Moderator
Beiträge: 4256
Registriert: 16.10.2002, 19:39
Echter Name: Christian Kulenkampff
Wohnort: Lüneburg

Re: [PHP + MySQL] Detailfragen zu Online-Highscore-Listen

Beitrag von Chromanoid »

Alles klar, ist erledigt. :)
joggel

Re: [PHP + MySQL] Detailfragen zu Online-Highscore-Listen

Beitrag von joggel »

Vielen dank...
ob das jetzt nun übertrieben ist oder nicht... sind halt Daten, über die allein nur ICH entscheiden sollte... :)
Benutzeravatar
Schrompf
Moderator
Beiträge: 4855
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: [PHP + MySQL] Detailfragen zu Online-Highscore-Listen

Beitrag von Schrompf »

Du bist, glaube ich, der Erste, der sich dagegen wehrt, wenn er in den Credits genannt wird. :) Sorry, mit so einer Reaktion hatte ich nicht gerechnet. Ich frage das nächste Mal nach.

Was die Reihenfolge der Einträge angeht, also Problem A - ich muss mich nochmal umfangreich dazu belesen, aber wenn ich das richtig verstehe, läuft es quasi darauf hinaus, alle Einträge aus dem Table zu lesen, zu sortieren, durchzunummerieren und dann erst den eigentlichen Query darauf loszulassen. Ist das nicht furchtbar ineffizient? Könnte man das Sortieren und Durchnummerieren nicht gleich beim Hinzufügen eines neuen Eintrags machen?

Problem B - Verschlüsselung: openssl ist ein guter Hinweis, gibt ja auch einige Libs dafür auf C++-Seite. Ist aber die Frage, ich ob das ganze Gebastel einer solchen Lib brauch, wenn ich nur verschlüsseln und entschlüsseln will. Es gibt ja für banale AES-Verschlüsselung auch fertige Funktionen in PHP und winzige Libs auf C-Seite - damit lässt sich das Problem wahrscheinlich lösen, ohne noch eine umfangreiche Lib zu den Dependencies hinzuzufügen.

Problem C - Parameter-Absicherung: da gäbe es einfach curl_easy_escape und auf PHP-Seite werden die URL-Parameter in $_REQUEST automatisch decodiert. Das klingt, als wäre es schon ein gelöstes Problem. Für die Konstruktion der SQL-Statements muss ich mich nochmal belesen - Danke für den Link, Exile.

Ich denke, ich mache das wie folgt:

Auf C++-Seite:
HTTP-Get oder Post Request erzeugen mit param=<verschlüsselte 256Bit>, wobei von den 32 Byte meinetwegen 2 Byte eine intern ergebene Table-ID sind, 4 oder 8 Byte die Punktzahl und die restlichen 22/26 Byte der Name. Also TableID, Name und Punktzahl in einen 32Byte-Buffer zusammenpacken, durch AES jagen, als URL kodieren und abschicken.

Auf PHP-Seite:
URL wird automatisch dekodiert. Param-String also entschlüsseln, TableID, Name und Punktzahl extrahieren, SQL-Query draus bauen und abschicken.

@Chromanoid: Danke für die Links - ich habe ehrlich gesagt nicht wirklich danach gesucht vorher. Die verlinkten Frameworks werden sicher auch solche Probleme lösen, aber ganz ehrlich - ich bin selten so einem riesigen Haufen Marketing Bullshit auf einmal begegnet. Mir wird übel, wenn jemand von "leverage social synergy" schwafelt. Nuja, jeder wie er mag. Ich musste eh endlich mal in PHP und MySQL fit werden und das hier war ein guter Anlass, sich mal mit dem Thema zu beschäftigen.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
eXile
Establishment
Beiträge: 1136
Registriert: 28.02.2009, 13:27

Re: [PHP + MySQL] Detailfragen zu Online-Highscore-Listen

Beitrag von eXile »

Schrompf hat geschrieben:Könnte man das Sortieren und Durchnummerieren nicht gleich beim Hinzufügen eines neuen Eintrags machen?
Kannst du machen. Du müsstest dann einen SQL-Trigger auf INSERT erstellen, welcher die Ränke von allen Benutzern, die eine geringere Score haben als das gerade einzufügende Element, um Eins inkrementiert.

Bitte beachte, dass du dadurch mehr Status in deiner Datenbank speicherst; Status, der eigentlich von der Datenbank deduziert werden kann, und damit unnötig ist. Wie bei statusbehafteten Systemen üblich hast du damit auch immer den Schrecken der Inkonsistenzen im Nacken; du musst also auch bei Bearbeitungen und Löschungen in der Tabelle entsprechende Aktualisierungen via Triggern durchführen. Meine Empfehlung: Erst einmal eine Datenbank mit ein paar Millionen Datensätzen generieren, und dann Zeitmessungen vornehmen, ob das wirklich zu einem Problem wird.
Benutzeravatar
Schrompf
Moderator
Beiträge: 4855
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: [PHP + MySQL] Detailfragen zu Online-Highscore-Listen

Beitrag von Schrompf »

Du hast Recht... erst muss es funktionieren, dann kann man sich Gedanken um die Performance machen.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Antworten