Datenkommunikation bei Multiplayer-Spielen von Tobias Lang, 8T Martin Mittring, 8T 08.12.2000 Einleitung Jeder Privatmensch bei uns kann sich heute eine Netzwerkkarte oder einen Internetzugang leisten. Das ermöglicht unter anderem echte Multiplayerspiele. Techniken wie ein geteilter Bildschirm, für jeden Spieler eine Hälfte, oder abwechseln der Spieler bieten dabei nicht die Vorteile wie ein Spiel über LAN oder WAN. Doch für den Spieleentwickler ergeben sich dadurch besondere Schwierigkeiten, deren hardwaretechnische Seite das Thema des Referates ist, genauer gesagt sind das hauptsächlich Antwortzeiten und Sicherheitsaspekte. Die Problematik der Antwortzeiten tritt nur bei Echtzeit-Spielen auf, denn hier ist eine schnelle Reaktion des Systems auf die Eingaben vom Spieler nötig. Die Sicherheitsaspekte sind vor allem bei Spielen im WAN wichtig, da man nicht darauf vertrauen kann, dass Mitspieler ihr Können ausschließlich durch faire Mittel beweisen. Angenommen wird, dass sich die Spieler schon gefunden haben, denn dafür gibt es einfache und unproblematische Lösungen. Inhaltsverzeichnis: 1. Architektur 2. Kompression 2.1 Nutzdaten komprimieren 2.2 Headergröße 2.3 Datenpakete zusammenfassen 3. Antwortzeit 3.1 Zeitverhalten innerhalb des Client 3.2 Entkopplung der beteiligten Systeme 3.3 Zeitverhalten in Verbindung mit WAN 3.4 Zeitverhalten bei Benutzung einer PPP Verbindung 3.5 Client-Side Prediction 4. Sicherheit 4.1. Notwendigkeit für Schutzmaßnahmen 4.2. Vorbemerkungen 4.3. Auswirkungen von Hackerangriffen 4.4. Angriffsformen und Gegenmaßnahmen 5. Zusammenfassung A Fragen B Literaturangaben C Anhang 1. Architektur Der Spieleentwickler muss sich vor dem Aufbau eines Multiplayerspieles festlegen, wie die Nachrichten verschickt werden. Es gibt zwei grundsätzliche Ansätze: a) Ein zentraler Server, der mit jedem Client Kontakt hält b) Jeder Client schickt an jeden anderen Client seine Nachrichten Meist wird der Ansatz a) gewählt. Die Unterschiede gegenüber b) sind: * Datenaufkommen niedrig 2*O(n), gegenüber O(n*n), skaliert bei vielen Clients deshalb besser als b) * Antwortzeiten doppelt so hoch wie bei b) * Synchronität der Clients untereinander einfach ( eine zentrale Instanz hält den Spielzustand ) * höhere Sicherheit ( Server kennt den Spielzustand, kann manipulierte Nachrichten vom Client erkennen ) Der Server kann auch gleichzeitig ein Client sein, sofern die Servertätigkeit nicht zu viel Rechenzeit beansprucht. Nachrichten müssen nur übertragen werden, wenn der Client auch direkt Verwendung dafür hat. Befinden sich z. B. die Spielerfiguren beider Clients in verschiedenen Raumabschnitten eines Levels, ist keine Kommunikation nötig. Problem dabei ist, wenn nun der Client einen neuen Raumabschnitt betritt, muss der Zustand des Ortes an ihn übertragen werden. Unter Umständen kann sich hier aber einiges angesammelt haben, was sich beim Spieler mit dem negativen Effekt eines Rucklers im Bildaufbau bemerkbar machen könnte. Es gibt aber auch andere Methoden um die Datenmenge gering zu halten. 2. Kompression Ein Datenpaket setzt sich aus den Nutzdaten und Verwaltungsinformationen zusammen. Ein Ziel ist es in möglichst viele Nutzdaten zu übertragen. Der Spieler allein produziert mit Maus, Tastatur und Joystick sehr wenig Input, (Sprachübertragung nicht berücksichtigt) die Auswirkungen der Eingaben können aber relativ groß werden. Meist überträgt man nicht die Eingaben, da diese sich immer auf den internen Zustand des Systems auswirken. Damit ein anderer Client die Eingaben auswerten kann, muss sein Systemzustand exakt der gleiche sein. Damit dürfen keine Pakte verloren gehen, die Reihenfolge der Pakete muss garantiert sein und die Clients müssen immer exakt synchron gehalten werden. Die Auswirkungen eines Spielers, können so allgemein sein, dass sie nicht vom internen Systemzustand abhängen. So ist es z. B. mit einer gewissen Toleranz egal, wann ein Heilzauber auf einen Mitspieler gesprochen wird. Sobald die Information beim Server vorliegt wird die Information in der Weltberechnung berücksichtigt. Würde man den Mausklick auf eine best. Bildschirmposition übertragen, so kann es sein, dass sich dort kein Spieler mehr befindet und der Spruch geht ins Leere, obwohl zum Zeitpunkt des Mausklicks sich dort ein Spieler befand. 2.1 Nutzdaten komprimieren Man kann hier 4 Arten unterscheiden: a) Deltakompression zu den Vorgängernutzdaten b) Statische verlustfreie Komprimierung (z. B. Orthonormale 3x3 Matrix in 3 Winkelangaben, Anwendung: Orientierung eines 3D Objektes) c) Statische verlustbehaftete Komprimierung (z. B. 32 Bit float in 16 Bit kodieren) d) Dynamische Komprimierung (z. B. Huffman, Deltakomprimierung innerhalb eines Paktes) e) dynamische verlustbehaftete Komprimierung (z. B. Sprachübertragungen) zu a) Hiermit wird man leider wieder abhängig vom internen Systemzustand, wird deshalb ungern verwendet. zu c) Typischerweise wird meist nur diese Art angewendet, wegen ihrer Einfachheit und Schnelligkeit. zu d) Die Datenmengen sind meist zu gering, als dass sich hier Aufwand lohnen würde. 2.2 Datenpaketgröße Die meisten Netzwerke heute nutzen TCP/IP. Ein Datenpaket setzt dabei wie folgt zusammen: * Nutzdaten = x Bytes * IP (Sender, Empfänger,...) = 20 Bytes Nun kann sich der Spieleentwickler zwischen TCP = 20 / 6* Bytes oder UDP = 8 (oder 34 je nach Literaturquelle) / 5* Bytes * = mit PPP-Kompression entscheiden. Für normale Anwendungen wird meist TCP verwendet. UDP garantiert nicht wie TCP die Reihenfolge und kümmert sich auch nicht automatisch darum, dass das Paket im Fehlerfall erneut angefordert wird. Dennoch oder besser gerade deshalb ist es für Echtzeitspiele die richtige Wahl. Wenn ein Paket A mit Positionsdaten verloren geht, das nächste Paket B aber die noch neueren Positionsdaten enthält, war das Paket A kein Verlust. Es erneut anzufordern und Paket B solange nicht zu bearbeiten würde den Spielfluß empfindlich stören. Bei sehr verschiedenen Paketinhalten kann man in nachfolgenden Pakten immer noch die Wichtigkeit der Vorgängerpakete mit übertragen und ob eine Neuanforderung sinnvoll wäre. Textnachrichten von Spielern haben hier sicher eine niedrige Priorität, eine Neuanforderung ist aber sinnvoll. Kopfbewegungen eines Spielers (durch kleine Mausbewegungen) haben auch niedrige Priorität, auf eine Neuanforderung kann bei hoher Netzlast aber verzichtet werden. 2.2 Datenpakete zusammenfassen Die Nutzdaten werden im Netz in Paketen verschickt. Offensichtlich ist es um so besser, je größer der Nutzdatenanteil, gegenüber dem Anteil der protokollbedingten Verwaltungsinformationen ist. Die Nutzdatenpakete sind meist viel kleiner als die maximale Größe eines Paketes. Sei z. B. ein Nutzdatenpaket 12 Bytes. Wenn 4 Nutzpakete zu einem zusammengefaßt werden können, so können die Verwaltungsinformationen von drei Paketen eingespart werden. Damit lassen sich in kürzerer Zeit mehr Nutzdaten übertragen. Dennoch kann das einen Nachteil haben. Wenn die Nutzdaten zu unterschiedlichen Zeiten übergeben werden, müssen die ersten 3 Pakete warten, bis das vierte übergeben wurde. Damit verschlechtert sich die mittlere Antwortzeit des Systems. Datenpakete zusammenfassen sollte man also nur dann, wenn viele und größere Nutzdaten übertragen werden müssen. Wenn die Nutzpakete zu spärlich auftreten, macht es Sinn diese vor der maximalen Ausnutzung bereist abzuschicken. 3. Antwortzeit Der Mensch erwartet auf seine Aktionen eine sehr schnelle Reaktion. Je nach Aktion akzeptiert der Mensch auch größere Antwortzeiten. Für Echtzeitspiele sollten diese unter 100ms liegen. Die Bildwiederholrate (FPS = frames per second) der Grafikdarstellung sollte über 15fps sein, um Bewegungen erkennen zu können. Für flüssige Bewegungen sind mindestens 30 FPS anzustreben. Wichtig für eine schnelle Reaktion auf eine neue Situation ist, dass die Varianz der Antwortzeit nicht zu groß ist. Leider hat das Zusammenfassen der Pakte im letzten Beispiel auch eine Vergrößerung der Varianz bewirkt. Ein Quake1 (oder Quake1World ?) Server läuft mit 10 FPS. Hier ist nicht die Bildwiederholrate gemeint, sondern die Rate in der die Nachrichten abgearbeitet werden. Die Rate mag sehr niedrig erscheinen, aber die Erfahrung zeigt, dass die Ergebnisse sehr gut sind. Inzwischen ist die Hardware besser geworden und die Ansprüche sind höher. Mehr als 20fps werden aber wohl nie nötig werden, weil hier der Mensch die Limitation darstellt. Der Server läuft mit einer fixen Rate um einen kontinuierlichen, konstanten Datenfluß zu erzeugen. Zudem lassen sich Datenpakete zusammenfassen und ein Client kann mit Zeitmessung leicht erkennen, wenn Nachrichten vom Server ausbleiben. 3.1 Zeitverhalten innerhalb des Client Auf der Grafik (siehe Anhang) ist ein typischer Client dargestellt. Die unterschiedlichen Komponenten sind mit Kreisen symbolisiert. Jede Komponente liefert ihre Ausgaben in bestimmten Taktraten an die anderen Komponenten weiter. Die großen Pfeile sind die Übertragungswege, auf denen die Daten unterschiedlich lange unterwegs sind. Hier erkennt man leicht, dass die Eingaben vom Benutzer einen langen Weg zurücklegen müssen, bis die Reaktion auf diese am eigenen oder an einem Mitspielerbildschirm erscheinen. Diese Zeit, die Antwortzeit, ist auch bei einem nicht Multiplayerspiel relativ lang. Die Antwortzeit eines Systems sollte nicht mit der Framerate verwechselt werden, in der die Grafik dargestellt wird. Bei für Spiele optimierter Hardware kann das so sein. So konnte man z. B. beim Amiga, der ja als Spielekonsole geplant war, die Maus mit der gleichen Rate abfragen, wie der Bildaufbau stattfand. Typische PC Systeme sind nicht auf Spiele optimiert. Die Daten werden in Nachrichtenpaketen übertragen, die in nicht definierten Zyklen (Jede Hardware kann es anders machen.) etliche Stationen durchlaufen, ehe sie bearbeitet werden können. Die Hauptschleife in der Grafik zeigt einen einfachen Aufbau. In einem Zyklus wird der Input geholt, dann der Weltzustand berechnet und diese schließlich visualisiert. Dieses System ist für nicht Multiplayerspiele typisch und bei Multiplayerspielen, die aus diesen hervorgingen war es oft zu finden. Damit alle Clients den gleichen Weltzustand berechnen, muss das System egal wie oft es pro Sekunde aufgerufen wird immer das gleiche Ergebnis liefern. Das ist bei vielen Spielen schwer bis unmöglich. Meist gibt dann einfach der langsamste Client die Framerate für alle anderen Clients vor (wie bei Doom). Um den gleichen Weltzustand auf verschiedenen PC Systemen zu gewähren, ist es sinnvoll die Darstellung von der Weltberechnung (Physik, KI, ...) zu trennen. Meist wird die Darstellung wesentlich öfter gemacht, als die Weltberechnung stattfindet. 3.2 Entkopplung der beteiligten Systeme Wegen des sehr unterschiedlichen Timings ist ein synchroner Betrieb aller beteiligten Komponenten (Input einlesen, Weltberechnung, Bildaufbau, Netzwerk) kaum möglich. Um die Komponenten maximal auszunutzen müssen diese asynchron laufen. So sollten die Clients untereinander entkoppelt sein, d.h. nicht der schwächste Rechner entscheidet über die Framerate des Spieles. Bei ersten Netzwerkspielen war das aber noch der Fall (Doom). Auch sollte die Weltberechnung von der Visualisierung der Welt entkoppelt sein. Die Genauigkeit der Physikberechnungen oder die Gegnerintelligenz sollte nicht mit der Rechengeschwindigkeit des Systems steigen. Alle Spieler sollen möglichst die gleichen Chancen haben. Bessere Reaktionszeiten wegen eines besseren Systems muss man allerdings akzeptieren. 3.3 Zeitverhalten in Verbindung mit WAN Für den Spieleentwickler unterscheidet sich das WAN gegenüber dem LAN in folgenden Punkten: a) kein IPX, nur TCP/IP (und UDP) b) Antwortzeiten länger (Router) c) Varianz der Antwortzeiten größer (Router) d) Wahrscheinlichkeit verlorener Pakte steigt (Router) e) Nachrichten werden nicht an alle Teilnehmer verschickt Für den Spieleentwickler bedeutet das WAN also nur stärkere Anforderungen gegenüber LAN. Wichtig für die Entwicklung sind Tests unter wirklichkeitsnahen oder realen Bedingungen. Am besten ist es, man erzeugt die Bedingungen künstlich. Man kann die Pakete im LAN gepuffert in unregelmäßigen Zeiten weitergeben oder zufällig löschen. Damit erspart man der Spielergemeinde die Probleme im echten WAN zu erleben. 3.4 Zeitverhalten bei Benutzung einer PPP Verbindung Wenn man sich mit einem Modem ins WAN einwählen will, wird zwischen dem eigenem Modem und dem Modem des Providers eine PPP Verbindung aufgebaut. Diese Verbindung hat einige besondere Eigenschaften. Das Modem, oder der Treiber des Modems kann Daten puffern, komprimieren oder Fehlerkorrekturen anwenden. Das erhöht die Antwortzeit und auch die Varianz. Am besten deaktiviert man die Datenkompression und Fehlerkorrektur, wenn möglich. Doch auch in der Kommunikation zwischen den Modems geht Bandbreite verloren. Die zu übertragenden Verwaltungsinformationen für TCP, UDP und IP lassen sich bei einer PPP Verbindung stark komprimieren. Leider ist das Verfahren nur bei TCP und IP Header üblich, obwohl es auch für UDP funktionieren kann. Als Spieleentwickler hat man das leider nicht in der Hand. Aus Effizienzgründen ist die PPP Verbindung synchron. In dem Datenstrom zwischen den beiden Modems müssen Steuerinformationen und Nutzdaten übertragen werden können. Hier tritt das Problem der Transparenz auf (Steuerdaten und Nutzdaten unterscheiden). So wird z.B. #7d und #7e für das Protokoll benutzt. Um die Mehrdeutigkeit zu den Nutzdaten zu beseitigen, wird ein Ausweichzeichen vorangestellt. Ist die "ACCM negotiation" aktiviert, so werden sogar die Zeichen von #00 bis #1f (32 Zeichen) auch mit Ausweichzeichen versehen. Die "ACCM negotiation" spart die Zeichen aus, damit Steueranweisungen sehr einfach in den Zeichenstrom integriert werden können. Vermutlich hängt das von der Hardware und Konfiguration des Providers ab, leider war hier die Literatur spärlich. Bei unglücklich gewählter Kodierung der Nutzdaten kann das bis zu einer Halbierung der Übertragungsgeschwindigkeit führen. Es ist also sinnvoll die Kodierung der Nutzdaten geschickt zu wählen. Oft sind sehr viele Nullbytes in den zu übertragenden Daten. Eine simple Addition kann diese aus dem #00 bis #1f Bereich herausschieben. PPP kann, je nach Konfiguration, bei gleichverteilten Bytecodes 0.8% oder 13.3% Overhead kosten. 3.5 Client-Side Prediction Die Client-Side Prediction ist ein Verfahren, bei dem man aus früheren Daten auf Daten schließt, die aber noch nicht vom Server bestätigt wurden. So kann angenommen werden, dass ein Spieler, der geradeaus lief, das auch etwas später noch tun wird. Anstatt den Spieler an seiner zuletzt bekannten Position festzuhalten wird anhand der Geschwindigkeit die neue Position errechnet. Kommt vom Server die richtige Information, muss meist nur wenig korrigiert werden. Zwar wird der Spielfluß merklich gesteigert, aber wenn Lags auftreten, werden Spieler an völlig falschen Positionen dargestellt, an denen sie nie waren. In Rogue Spear z. B. laufen die Spieler manchmal hinter ihren Deckungen heraus, nur weil sie eine kleine Vorwärtsbewegung gemacht haben. Für den steuernden Spieler ist alles OK, doch für die anderen hat dieser die Deckung verlassen. Nach dem Lag springt der Spieler wieder hinter seine Deckung. Auswirkung über die Darstellung hinaus sollte eine Fehlvorhersage aber nicht haben. Ein Geschoß würde den Spieler nicht treffen, da der Server derartig wichtige Entscheidungen erst treffen darf, wenn alle wichtigen Datenpakete von den Clients vorliegen. 4. Sicherheit 4.1. Notwendigkeit für Schutzmaßnahmen Der Verkaufserfolg und Ruf von einem Multiplayerspiel hängt heute auch davon ab wie sicher das Spiel ist und ob es möglich ist unfaire Mittel einzusetzen. Eine wichtige Kaufentscheidung stellt bei bestimmten Genres eine Multiplayer-Option dar, die Firmen betreiben mit solch einem Feature explizit Werbung, so dass der Kunde somit eine entsprechende Gegenleistung erwartet. Die besteht in Form eines fairen Spiels! Besondere Bedeutung gewinnen Sicherheitsaspekte bei Online-Wettkämpfen für die Preisgelder vergeben werden. Da in Zukunft der Anteil an Massiv-Multiplayer-Spielen zunehmen sind bei der Entwicklung und Konzeption einige Punkte in Bezug auf Sicherheit zu beachten. Schließlich gehen die Überlegungen schon so weit, dass Online-Spiele "on-demand" mit neuen Zusatzmission, neuen Welten usw. zu erweitern. Für diese Dienstleistungen ist reales Geld zu entrichten wodurch die Sicherheit eine noch grössere Rolle spielen wird. 4.2. Vorbemerkungen Normalerweise geht man von einem sicheren Sender und Empfänger aus, die über eine unsichere Leitung kommunizieren. Doch gerade bei Spielen darf nicht von einem sicheren Client ausgegangen und darauf vertraut werden, dass der Spieler keine Modifikationen an den Daten und der Executable durchführt. Zu bedenken ist, dass mit dem Spiel alle Daten und die Client-Exe ausgeliefert wird, die alle Algorithmen zur Datenkommunikation und Datenverschlüsselung enthält. Hinzu kommt das jeder Zugriff auf die gleichen Entwicklungswerkzeuge wie Compiler, Debugger, usw. hat, die für die Herstellung des Produkts eingesetzt wurden. Der Server ist i. d. R. die einzige sichere Einheit, er hält den aktuellen Zustand des Spiels aufrecht, überprüft und nimmt alle Kommandos der Clients an, um den Zustand der Simulation zu aktualisieren. Ein einziger böswilliger Eingriff kann bei einem Spiel mit Tausenden von Teilnehmern bereits das System destabilisieren. Obwohl eine Client-Client Kommunikation möglich wäre (z. B. Chat/Voice) gehen wir immer von der Annahme aus, dass die Datenkommunikation zwischen Client und Server stattfindet. Des weiteren wird eine paketorientierte Übertragung angenommen, bei der jedes Paket aus Header und Nutzdaten (Payload) besteht. Ziel des Netzwerkprotokolles ist es die Originaldaten vom Sender an den Empfänger zu liefern. Jede Art der Modifikation der Sendesequenz von den Nutzdaten soll erkannt werden. 4.3. Auswirkungen von Hackerangriffen Bevor wir auf die Angriffsformen eingehen, beschreiben wir zunächst einmal die Auswirkungen auf ein laufendes Spiel, die durch Hackerangriffe hervorgerufen werden. Spiele, die schnelle Reflexe und rasche Reaktionszeiten abverlangen können durch Computerprogramme, sogenannte Bots oder Trainer, beeinflusst werden. Hierbei ermitteln sie die Pakete, die für die Steuerung und Bewegung des Spielers zuständig sind. Mit diesen Daten simuliert ein Computerprogramm den menschlichen Spieler, indem er zielgerichtet die Daten gegen seine Gegner anwendet und an den Server schickt. Bei dem Actionspiel Quake beispielsweise ließen einige Spieler Bots für sich spielen, um die eigene Treffergenauigkeit zu erhöhen. Man hat zwar durch ein Update versucht Spieler, die ein unrealistisch hohe Trefferwahrscheinlichkeiten hatten automatisch aus dem Spiel zu nehmen, doch leider waren auch Spieler dabei, die keine Bots benutzten und tatsächlich so gut spielten. Bei vielen Strategiespielen gibt es eine Kartenansicht mit allen vom Spieler steuerbaren Einheiten und der geographischen Umgebung. Nun sind in der Regel nur kleine Teile von dem Spielfeld aufgedeckt, die bereits erforscht sind. Die andere Bereiche bleiben somit für den Spieler nicht sichtbar. Für ihn ist somit unklar welche Bewegungen die gegnerische Einheiten vornehmen, was ein wichtiger Bestandteil des Spielprinzips darstellt. Mit Hilfe eines Debuggers ist es nicht schwer die Variable im Speicher ausfindig zu machen, die für die Sichtbarkeit der kompletten Karte zuständig ist. In diesem Fall fand der Angriff nicht bei der eigentlichen Übertragung der Daten an den Server statt, sondern auf einen lokalen Speicherbereich der Executable. Solche Fälle kann man erkennen, aber nicht effektiv verhindern, indem der Server überprüft, ob ein Objekt, das der Spieler auf der Karte markiert hat auch wirklich vom Spieler gesehen werden kann. Denn die Daten für die Einheiten sind vom Client abrufbar und die Sichtbarkeit der Karte wird nur über ein Flag gesteuert. 4.4. Angriffsformen und Gegenmaßnahmen 4.4.1 Packet Tampering (Paketmanipulation) Die einfachste Form des Angriffs besteht darin irgendwelche Bytes zu ändern und zu schauen was passiert. Entsprechend primitiv ist die Gegenmaßnahme in Form von der Bildung eine Prüfsumme über das komplette Paket. Der Sender berechnet die Prüfsumme des Pakets, überträgt sowohl die Daten als auch die dazugehörige Prüfsumme an den Empfänger, der dann seinerseits eine Prüfsumme errechnet. Diese wird anschließend mit der empfangenen Prüfsumme verglichen. Stimmen sie nicht überein kann der Empfänger ein Wiederholen des Pakets auffordern. Wichtig bei diesem Mechanismus ist, dass die Prüfsumme nicht nur von den Nutzdaten zu bilden, sondern der Header mit einbezogen wird. Nun gibt es zwei Schwächen einer einfachen Prüfsumme. Zum einen enthält die Executable den Code für die Bildung der Prüfsumme, die von einem Angreifer jederzeit durch Reverse Engineering bestimmt werden kann, und zum anderen können gültige Pakete eingefangen und zu einem späteren Zeitpunkt wieder verschickt werden. Man spricht dann vom sogenannten Packet Replay-Attack. Ein einfache Prüfsummenbildung ist somit alleine nicht ausreichend, deshalb sollten Pakete mit gleichen Nutzdaten kaum eine Korrelation in ihrem Bitmuster zeigen um Auswertungen dieser Daten zu erschweren. Durch eine leichte Modifikation der Daten mit dem XOR-Operator und einer Zufallszahl lässt sich beispielsweise sehr einfach ein variables Bitmuster erzeugen. Der Empfänger muss synchron die gleiche Zufallszahlenfolge erzeugen, um die Daten zu entschlüsseln. 4.4.2 Packet Replay (Paketwiederholung) Beim Packet Replay wird von einem böswilligen Benutzer ein Paket vom Client kopiert und mehrmals an den Server gesandt. Diese Technik wird unter anderem dazu benutzt Kommandos schneller ausführen zu lassen als gewöhnlich vom Spiel erlaubt wären, beispielsweise die Erhöhung der Schussfrequenz einer Waffe. Der Entwickler könnte versuchen diesen speziellen Angriff durch einen Timer auf der Serverseite zu unterbinden, der garantiert, dass nur ein Kommando in einem bestimmten Zeitintervall vom Client akzeptiert wird. Obwohl dadurch die meisten Packet-Replay-Angriffe entdeckt werden, ist ein Timer nicht praktikabel, da Verzögerungen im Netzwerk zu Häufungen von Paketen führen, die dann zur gleichen Zeit am Server ankommen würden. Dies hätte zur Folge, dass gültige Pakete ignoriert werden. Deshalb ist es besser zu jedem Paket einige Statusinformationen hinzuzufügen, so dass trotz gleicher Nutzdaten ein Paket immer ein anderes Bitmuster erhält. Hierfür kann z. B. eine Nummer erzeugt werden, die fortlaufend hochgezählt wird. Besser ist es allerdings eine Zustandsmaschine zu implementieren, die sukzessive ID-Nummern für jedes Paket erzeugt. Das schwierige an dieser Methode ist, die Generatoren der Zustandsmaschinen von Sender und Empfänger zu synchronisieren. Eine Möglichkeit besteht darin, dass sich Sender und Empfänger am Anfang auf einen Wert einigen, mit dem sie beginnen und ihre Zustandsmaschinen initialisieren. Ein weiterer Schutz besteht darin die Paketlänge absichtlich mit zufälligen Nutzdaten zu variieren, die nicht benutzt werden. Somit wird verhindert das aufgrund der Paketlänge Rückschlüsse auf den Verwendungszweck des Pakets geschlossen werden. Die Größe der unbenutzbaren Daten wird ebenfalls über eine synchronisierte Zustandsmaschine bei Sender und Empfänger ermittelt. Der Sender vergrößert die nach aussen gehenden Daten entsprechend und der Empfänger ignoriert die angehängten Daten. Diese Maßnahme muss allerdings auf die notwendige Bandbreite abgestimmt sein. 4.4.4 Reverse Engineering Das am schwersten zu bekämpfende Problem bei Angriffen auf Protokolle stellen die Verschlüsselungsalgorithmen dar, die jederzeit durch Reverse Engineering bestimmbar sind. Daher gilt es bei der Entwicklung und Implementierung einige Punkte zu beachten: * Alle Symbole und Debugging-Informationen müssen entfernt werden bevor irgend etwas freigegeben wird. * Verschlüsselungs- und Entschlüsselungsalgorithmen dürfen nicht in eigenen Funktionen isoliert werden, sondern sollten statt dessen mit anderen Netzwerk Programmteilen kombiniert sein. Dies ist eine der wenigen Stellen, an denen es sinnvoll, ist auf die Wartbarkeit von Quellcode zu verzichten. * Magic-Numbers, wie zum Beispiel Anfangswerte für Zufallsgeneratoren oder Zustandsmaschinen, sollten dynamisch zur Laufzeit generiert werden und nicht als feste Konstanten in der Executable auftauchen. * Markante Werte wie zum Beispiel 800 Punkte für Holzresourcen oder ähnliches sollten nie in unverschlüsselter Form in den Datenstrukturen vorkommen. Eine einfache XOR-Operation kann man zum Schutz solcher Daten benutzen: Code-Beispiel: void SetWood(int Wood_Amount) { GameResourceAmount[RESOURCE_WOOD] = Wood_Amount ^ EncryptValue[RESOURCE_WOOD]; } int GetWood() { return GameResourceAmount[RESOURCE_WOOD] ^ EncryptValue[RESOURCE_WOOD]; } * Jede Version vom Client d.h. auch frühe Betas sollten all die zuvor genannten Maßnahmen enthalten. Sonst könnte der Angreifer unverschlüsselte Bytestreams aufzeichnen und sie als Vergleichsobjekte für spätere Versionen benutzen, die eine Verschlüsselung einsetzen. 5. Zusammenfassung Viele Aspekte der klassischen Datenkommunikation lassen sich bei Multiplayerspielen in LAN oder WAN wiederfinden. Berücksichtigt man die besonderen Umstände bei Multiplayerspielen, kann man auch klassische Verfahren der Datenkommunikation hier anwenden. Bereits bei der Konzeption von Massiv-Multiplayer-Spielen gilt es Sicherheitsaspekte zu berücksichtigen und dabei die Antwortzeiten gering zu halten. Es kann kein absolut sicheres Protokoll zum Schutz vor Hackerangriffe geben. Es sollte ein guter Kompromiß gefunden werden, zwischen einem sehr sicheren System und einem System das sehr gute Antwortzeiten leistet. A Fragen 1.) Was versteht man unter Packet Replay, und nennen Sie die mögliche Abwehrtechnik. * Bei Packet Replay werden Pakete wiederholt und in kürzeren Zeitintervallen als erlaubt an den Server geschickt. * Zum Schutz vor solchen Angriffen kann man die Pakete mit IDs kennzeichnen, die beim Empfänger mit seiner von einer Zustandsmaschine erzeugten ID vergleicht. Stimmen sie nicht überein wird das Paket nicht akzeptiert. 2.) Was sind die beiden generellen Angriffspunkte bei Massiv-Multiplayer-Spielen? * Der Client und der Datenübertragungsweg sind unsicher. 3.) Was ist der Unterschied zwischen einer UDP/IP und einer TCP/IP Verbindung?` * TCP/IP garantiert die Reihenfolge der Pakete und fordert bei fehlerhafter Übertragung das Paket automatisch neu an, bei UDP ist das nicht der Fall. Deshalb hat UDP/IP die kürzeren Antwortzeiten. 4.) Welche 2 Zeile hat man im Bezug auf das Zeitverhalten einer Echtzeitspieleengine? * Die Antwortzeit und die Varianz der Antwortzeit ist zu minimieren. B Literaturangaben * Game Programming Gems, Artikel von Andrew Kirmse * www.gamedev.net * www.gamasutra.com C Anhang 2