Anti-Cheating Best Practices

Introduction

Fighting cheating is important, especially in multiplayer games. The game industry is full of famous titles that were wasted by “trainers”, “proxies” or other tools to get an edge upon other players.

You should know your game will be attacked, especially if there is something at stake (real or virtual money, social status, rank, achievements, etc.).

The main problem is that the Game State data is located at the client level and is passed by the Scalable Server from one client to the next. So in theory, a rogue or hacked client could uncover the entire knowledge of the game, like the hidden information of other players or of the game itself. It could also corrupt the data to twist them to its advantage.

As always with security, there is no silver bullets. The right approach is a system of layered defenses. But it can be complicated and a source of bugs if it is not properly conducted. So it is important to understand the possible threats, the level of their security risks, and their solutions.

There are two types of possible attacks: Data Peeking and Data Corruption.

Data Peeking

Data Peeking is about reading hidden or restricted information.

Listening on the wire

Also called “man in the middle” attack, this attack is about using some software to read the data exchanged between the client and the server on the network. There are a number of tools that allow you to do this, from network analyzers to proxies. Proxies are probably the easiest ones to use.

To counter this attack, you must use TLS to encrypt all communications between your game and the Scalable Server. But this won’t be enough, because there are solutions to fake certificates or identities. So we highly recommend using a technique called “Certificate and Public Key Pinning”. You will find a good explanation in the TLS Public Key Pinning section.

This being said, this type of attack is not the highest threat, because the collected data is a pain to analyze. Protobuf blocks are in binary format and would have to be decoded, as well as the game data itself. You can encrypt your game data, but it would be like redoing what TLS already provides, so we still recommend using the Certificate and Public Key Pinning technique, which will deal with the problem.

The next attack is more common.

Reading the Game State from RAM

This is a common and easy attack, especially on desktop machines. All it takes is a tool that monitors the RAM space of the game and looks for specific patterns (there are some specialized software to do this). With some practice while watching the game in action, it becomes easy to spot some key values: number of lives, score, lists, etc. This attack brings the most value for the least efforts. It can be used to read the other players’ hand, the next cards from the deck, etc.

Moreover, this attack is difficult to detect by other players. They may have the uneasy feeling that their opponent is reading their hand over their shoulder but they won’t be able to prove anything.

The solution: the Replay Data Model

Instead of being a “snapshot” of the game at a current point in time, the Game State should contain the list of all players’ actions since the very beginning of the game. When a client receives the Game State from the Scalable Server, it should replay the entire list of actions through its game engine to reconstruct the current state of the game.

It is not as bad as it seems. Most likely, this is already what you are doing: if you want to implement asynchronous gaming properly, you will need to display the previous players’ actions when a player resumes an ongoing game.

Moreover, storing the game history brings a lot of side benefits that you should consider:

  • Development tools: by using a Replay-based data model, it will become much easier to debug your game engine. This allows you to trace the entire course of a game and find when something went wrong. It is also a great way to build test fixtures for the Integration or Acceptance Tests of your game engine: once you fixed the bug using a game dataset, keep it for your tests to make sure that you won’t have any regressions. You should also provide a way for your Beta-testers to send you their game data when they encounter a problem: you will be able to replay their game and find out what happened. It’s better and more accurate than any hand-written bug report!

  • Replay feature: this also opens the door to providing an automatic recording with a Replay feature in your app. This is a terrific feature, especially for tournaments.

You will find more details (with code and data model snippets) in the Event Sourcing section of the Best Practices chapter.

When you run the game actions through your game engine, don’t build the data you don’t need. For example, if it’s the turn of player A, don’t build the hands of players B and C. You probably only need to keep the number of cards that they have. Not building sensitive data is an easy and efficient way to hide it!

If you need to build data, prefer volatile storage (stack-based) rather than permanent storage (allocated blocks in RAM). If you really need to store data (lists, object members, etc.), encrypt them. “Obscurity is not security” but it helps tiring hackers.

Generally speaking, prefer generating data based on code rather than data structures. For example, let’s consider a pile of cards to draw from. You could think of making a list and shuffling it. A better approach is to use a pseudo-random seed value and a deterministic deck generator. You only store the seed value and the top card index. When a player picks a card from the top of the pile, you simply use your algorithm to find out which card it is.

If you need to store your game data in a local file (for example for a resume game feature), make sure you encrypt it. Reading files is just too easy.

Data Corruption

Data Corruption is about changing the game data in order to turn the game to the cheater’s advantage. It’s probably the developer’s worst nightmare, especially because corrupted data can have ripple effects and make the other clients behave improperly.

For example, a hacker could create better cards and add them to his hand rather than picking them from the draw pile (a technique called “Erwin’s Cheating” at Asmodee.net). Or a hacker could pick another card inside the draw pile rather than the one at the top.

Solutions

Since we are using the Replay Data Model, the game engine can be highly defensive by checking all actions against the game rules. Again, you are most likely already doing this: rules verification should happen at the game engine level, not only at the user interface level. If something fishy happens, reject the data and abort the game.

We also recommend that you digitally sign your game data. And insert time-dependent values inside your game data, like a timestamp for each action. Any technique that allows your game engine to detect something illogical is a weapon against data corruption.

Feature Exploits

Beyond technical attacks, some features of your game can be used by players to cheat. So you should consider these carefully as this will impact your game design:

  • Observe: the Observe feature is a wonderful feature, especially for tournaments: it allows other users to watch an on-going game. But some of these users could be accomplices of the players, so make sure you provide options for the player creating the game to hide key elements, such as the players’ hands and so on. And apply the Data Peeking techniques to make sure that you don’t create the data related to these key elements.

  • Multiple Accounts / Multiple Clients: some players use multiple accounts and play on several devices at the same time. One account would be the player’s main account and another one would be the “helper” account, used to favor the main account. This is one reason why the online games history is public on all players’ profile on the Days of Wonder web site. This allows the community to self-manage itself. Top ranked players are in the spotlight, and so are always the subject of careful studies by other players. Moreover, providing a Replay feature goes an extra step in helping the community to monitor itself.