How to Stop People Hacking the PHP-Based Highscore Table of a Flash Game

What is the best way to stop people hacking the PHP-based highscore table of a Flash game

This is a classic problem with Internet games and contests. Your Flash code works with users to decide a score for a game. But users aren't trusted, and the Flash code runs on the user's computer. You're SOL. There is nothing you can do to prevent an attacker from forging high scores:

  • Flash is even easier to reverse engineer than you might think it is, since the bytecodes are well documented and describe a high-level language (Actionscript) --- when you publish a Flash game, you're publishing your source code, whether you know it or not.

  • Attackers control the runtime memory of the Flash interpreter, so that anyone who knows how to use a programmable debugger can alter any variable (including the current score) at any time, or alter the program itself.

The simplest possible attack against your system is to run the HTTP traffic for the game through a proxy, catch the high-score save, and replay it with a higher score.

You can try to block this attack by binding each high score save to a single instance of the game, for instance by sending an encrypted token to the client at game startup, which might look like:

hex-encoding( AES(secret-key-stored-only-on-server, timestamp, user-id, random-number))

(You could also use a session cookie to the same effect).

The game code echoes this token back to the server with the high-score save. But an attacker can still just launch the game again, get a token, and then immediately paste that token into a replayed high-score save.

So next you feed not only a token or session cookie, but also a high-score-encrypting session key. This will be a 128 bit AES key, itself encrypted with a key hardcoded into the Flash game:

hex-encoding( AES(key-hardcoded-in-flash-game, random-128-bit-key))

Now before the game posts the high score, it decrypts the high-score-encrypting-session key, which it can do because you hardcoded the high-score-encrypting-session-key-decrypting-key into the Flash binary. You encrypt the high score with this decrypted key, along with the SHA1 hash of the high score:

hex-encoding( AES(random-128-bit-key-from-above, high-score, SHA1(high-score)))

The PHP code on the server checks the token to make sure the request came from a valid game instance, then decrypts the encrypted high score, checking to make sure the high-score matches the SHA1 of the high-score (if you skip this step, decryption will simply produce random, likely very high, high scores).

So now the attacker decompiles your Flash code and quickly finds the AES code, which sticks out like a sore thumb, although even if it didn't it'd be tracked down in 15 minutes with a memory search and a tracer ("I know my score for this game is 666, so let's find 666 in memory, then catch any operation that touches that value --- oh look, the high score encryption code!"). With the session key, the attacker doesn't even have to run the Flash code; she grabs a game launch token and a session key and can send back an arbitrary high score.

You're now at the point where most developers just give up --- give or take a couple months of messing with attackers by:

  • Scrambling the AES keys with XOR operations

  • Replacing key byte arrays with functions that calculate the key

  • Scattering fake key encryptions and high score postings throughout the binary.

This is all mostly a waste of time. It goes without saying, SSL isn't going to help you either; SSL can't protect you when one of the two SSL endpoints is evil.

Here are some things that can actually reduce high score fraud:

  • Require a login to play the game, have the login produce a session cookie, and don't allow multiple outstanding game launches on the same session, or multiple concurrent sessions for the same user.

  • Reject high scores from game sessions that last less than the shortest real games ever played (for a more sophisticated approach, try "quarantining" high scores for game sessions that last less than 2 standard deviations below the mean game duration). Make sure you're tracking game durations serverside.

  • Reject or quarantine high scores from logins that have only played the game once or twice, so that attackers have to produce a "paper trail" of reasonable looking game play for each login they create.

  • "Heartbeat" scores during game play, so that your server sees the score growth over the lifetime of one game play. Reject high scores that don't follow reasonable score curves (for instance, jumping from 0 to 999999).

  • "Snapshot" game state during game play (for instance, amount of ammunition, position in the level, etc), which you can later reconcile against recorded interim scores. You don't even have to have a way to detect anomalies in this data to start with; you just have to collect it, and then you can go back and analyze it if things look fishy.

  • Disable the account of any user who fails one of your security checks (for instance, by ever submitting an encrypted high score that fails validation).

Remember though that you're only deterring high score fraud here. There's nothing you can do to prevent if. If there's money on the line in your game, someone is going to defeat any system you come up with. The objective isn't to stop this attack; it's to make the attack more expensive than just getting really good at the game and beating it.

How to secure scorelist in flash game

In terms of decompilation, I think code obfuscation is something you should consider. It should make data tracking all the more difficult for people who decompile your code.

In any case, keep in mind that if someone REALLY wants to break your security, they can and will. See: PS3 online services. Some precautions are good, to keep average Joes away from trying to break your high scores, but there's only so much you can do.. getting hacked is inevitable really.

In terms of scoreboard protection in PHP, see this question, it has numerous wonderful suggestions: What is the best way to stop people hacking the PHP-based highscore table of a Flash game

Reporting true game scores in Flash & PHP

Your hash does not increase the security, but only the obscurity of your system, i.e. it makes it harder to enter fake scores in practice, but the theoretical hurdle stays the same. Wikipedia has more on this class of "security". Any form of checksums and encryption will do nothing against an attacker who reverse-engineered your application's protocol - and that's hard, but not nearly has hard as it sounds.

The only hope you can have is to modify a significant portion of the game to a machine you control, i.e. your server. For example, a good idea might be for the client to send a "replay file" which contains all actions the user inputted, replay the game on the server, and then calculate the score on the server.

How to prevent cheating on a flash game by slowing down cpu?

You could have a repeating timer with a short interval, 100ms or so, and check new Date().getTime() on each tick. By default, a new Date has the current system time, and getTime() gives you the time in milliseconds for a simpler comparison. Compare that with a start time and end the game once at least 30 seconds have passed. Something like:

import flash.utils.Timer;
import flash.events.TimerEvent;

var ticker:Timer = new Timer(100, 0);
ticker.addEventListener(TimerEvent.TIMER, checkElapsedTime);

var startTime:Number = new Date().getTime();
ticker.start();

function checkElapsedTime(e:TimerEvent):void {

var now:Number = new Date().getTime();

if (now - startTime >= 30 * 1000) {

// End the game and stop the ticker.

ticker.stop();
ticker.removeEventListener(TimerEvent.TIMER, checkElapsedTime);
}

}

There is obviously still some slight lag if the timer is very slow, so just in case I would run the same check when an answer is submitted and ignore it if it was after the deadline.

Finally, to check if a user has changed their system clock you could store the previous now and make sure the new now is always larger.

Anti-hacking a game - best practices, suggestions

This question over at GameDev SE has what you're looking for:

https://gamedev.stackexchange.com/questions/4181/how-can-i-prevent-cheating-on-global-highscore-tables

Another discussion on SO about the topic:
Suggestions for (semi) securing high-scores in Flash/PHP game

The summary is that while there are many methods to make cheating difficult, eventually somebody with enough time in their hands will bypass your security measures. The only way to make leader boards hacker proof is to run the game logic on the server.

How can you prevent bogus high scores from appearing on a global high score list?

For a PC game where the score is generated by the client, this is not a solvable problem since the client is inherently untrustworthy.

The only thing you can try to do is make it harder for someone to submit a fake score.

Some thoughts:

  • Protect the in-memory score.
    You can use API's like CryptProtectMemory to hide the score in memory - a simple memory write will not work. However, with an attached debugger or via injecting code into your process, they could still modify the score. You can look into various schemes for trying to defeat debuggers.

  • Protect the score en-route to the server.
    You can encrypt the data being sent to the service, as you suggest, but since the untrusted party has control over the key, this is merely obfuscation and offers no solid protection.

  • Validate the score at the service.
    I'd be loathe to do this, beyond very simple checks. A bug here will result in you rejecting valid scores. It'll be impossible to distinguish between cheaters and strong players.

At this point, you really have to ask your self if the engineering effort is really worth it. What if someone posts an invalid score? What do you actually lose? I would do the bare minimum to protect against a kid with a simple script. I.e., don't have your score submission be just:

http://myservice.com/submitscore.aspx?PlayerName=Michael&Score=999999999

I would just use simple protection in memory against casual snoops, some simple obfuscation on the wire (hash the score with a server cookie) and be done.

How can i prevent Cheat engine for my single player flash games?

Yes you can:

this is a really good and easy way to do it.

http://www.riawolf.com/?p=20



Related Topics



Leave a reply



Submit